2 // This file is part of Moodle - http://moodle.org/
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 * Edit and review page for grade categories and items
20 * @package core_grades
21 * @copyright 2008 Nicolas Connault
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 require_once '../../../config.php';
26 require_once $CFG->dirroot
.'/grade/lib.php';
27 require_once $CFG->dirroot
.'/grade/report/lib.php'; // for preferences
28 require_once $CFG->dirroot
.'/grade/edit/tree/lib.php';
30 $courseid = required_param('id', PARAM_INT
);
31 $action = optional_param('action', 0, PARAM_ALPHA
);
32 $eid = optional_param('eid', 0, PARAM_ALPHANUM
);
33 $category = optional_param('category', null, PARAM_INT
);
34 $aggregationtype = optional_param('aggregationtype', null, PARAM_INT
);
36 $url = new moodle_url('/grade/edit/tree/index.php', array('id' => $courseid));
38 $PAGE->set_pagelayout('admin');
40 /// Make sure they can even access this course
41 if (!$course = $DB->get_record('course', array('id' => $courseid))) {
42 print_error('nocourseid');
45 require_login($course);
46 $context = context_course
::instance($course->id
);
47 require_capability('moodle/grade:manage', $context);
49 // todo $PAGE->requires->js_module() should be used here instead
50 $PAGE->requires
->js('/grade/edit/tree/functions.js');
52 /// return tracking object
53 $gpr = new grade_plugin_return(array('type'=>'edit', 'plugin'=>'tree', 'courseid'=>$courseid));
54 $returnurl = $gpr->get_return_url(null);
56 // Change category aggregation if requested
57 if (!is_null($category) && !is_null($aggregationtype) && confirm_sesskey()) {
58 if (!$grade_category = grade_category
::fetch(array('id'=>$category, 'courseid'=>$courseid))) {
59 print_error('invalidcategoryid');
62 $data = new stdClass();
63 $data->aggregation
= $aggregationtype;
64 grade_category
::set_properties($grade_category, $data);
65 $grade_category->update();
67 grade_regrade_final_grades($courseid);
70 //first make sure we have proper final grades - we need it for locking changes
71 grade_regrade_final_grades($courseid);
73 // get the grading tree object
74 // note: total must be first for moving to work correctly, if you want it last moving code must be rewritten!
75 $gtree = new grade_tree($courseid, false, false);
82 if (!$element = $gtree->locate_element($eid)) {
83 print_error('invalidelementid', '', $returnurl);
85 $object = $element['object'];
88 $switch = grade_get_setting($course->id
, 'aggregationposition', $CFG->grade_aggregationposition
);
90 $strgrades = get_string('grades');
91 $strgraderreport = get_string('graderreport', 'grades');
96 if ($action == 'moveselect') {
97 if ($eid and confirm_sesskey()) {
103 $grade_edit_tree = new grade_edit_tree($gtree, $movingeid, $gpr);
107 if ($eid && confirm_sesskey()) {
108 if (!$grade_edit_tree->element_deletable($element)) {
109 // no deleting of external activities - they would be recreated anyway!
110 // exception is activity without grading or misconfigured activities
113 $confirm = optional_param('confirm', 0, PARAM_BOOL
);
116 $object->delete('grade/report/grader/category');
117 redirect($returnurl);
120 $PAGE->set_title($strgrades . ': ' . $strgraderreport);
121 $PAGE->set_heading($course->fullname
);
122 echo $OUTPUT->header();
123 $strdeletecheckfull = get_string('deletecheck', '', $object->get_name());
124 $optionsyes = array('eid'=>$eid, 'confirm'=>1, 'sesskey'=>sesskey(), 'id'=>$course->id
, 'action'=>'delete');
125 $optionsno = array('id'=>$course->id
);
126 $formcontinue = new single_button(new moodle_url('index.php', $optionsyes), get_string('yes'));
127 $formcancel = new single_button(new moodle_url('index.php', $optionsno), get_string('no'), 'get');
128 echo $OUTPUT->confirm($strdeletecheckfull, $formcontinue, $formcancel);
129 echo $OUTPUT->footer();
136 //TODO: implement autosorting based on order of mods on course page, categories first, manual items last
140 if ($eid and confirm_sesskey()) {
141 $moveafter = required_param('moveafter', PARAM_ALPHANUM
);
142 $first = optional_param('first', false, PARAM_BOOL
); // If First is set to 1, it means the target is the first child of the category $moveafter
144 if(!$after_el = $gtree->locate_element($moveafter)) {
145 print_error('invalidelementid', '', $returnurl);
148 $after = $after_el['object'];
149 $sortorder = $after->get_sortorder();
152 $parent = $after->get_parent_category();
153 $object->set_parent($parent->id
);
155 $object->set_parent($after->id
);
158 $object->move_after_sortorder($sortorder);
160 redirect($returnurl);
168 //if we go straight to the db to update an element we need to recreate the tree as
169 // $grade_edit_tree has already been constructed.
170 //Ideally we could do the updates through $grade_edit_tree to avoid recreating it
171 $recreatetree = false;
173 $normalisationmessage = null;
175 if ($data = data_submitted() and confirm_sesskey()) {
176 // Perform bulk actions first
177 if (!empty($data->bulkmove
)) {
180 foreach ($data as $key => $value) {
181 if (preg_match('/select_(ig[0-9]*)/', $key, $matches)) {
182 $elements[] = $matches[1];
186 $grade_edit_tree->move_elements($elements, $returnurl);
189 // Update weights (extra credits) on categories and items.
190 foreach ($data as $key => $value) {
191 if (preg_match('/^weight_([0-9]+)$/', $key, $matches)) {
194 $value = unformat_float($value);
195 $value = clean_param($value, PARAM_FLOAT
);
197 $grade_item = grade_item
::fetch(array('id' => $aid, 'courseid' => $courseid));
199 // Convert weight to aggregation coef2.
200 $aggcoef = $grade_item->get_coefstring();
201 if ($aggcoef == 'aggregationcoefextraweightsum') {
202 // The field 'weight' should only be sent when the checkbox 'weighoverride' is checked,
203 // so there is not need to set weightoverride here, it is done below.
204 $value = $value / 100.0;
205 $grade_item->aggregationcoef2
= $value;
206 } else if ($aggcoef == 'aggregationcoefweight' ||
$aggcoef == 'aggregationcoefextraweight') {
207 $grade_item->aggregationcoef
= $value;
210 $grade_item->update();
212 $recreatetree = true;
214 // Grade item checkbox inputs.
215 } elseif (preg_match('/^(weightoverride)_([0-9]+)$/', $key, $matches)) {
216 $param = $matches[1];
218 $value = clean_param($value, PARAM_BOOL
);
220 $grade_item = grade_item
::fetch(array('id' => $aid, 'courseid' => $courseid));
221 $grade_item->$param = $value;
223 $grade_item->update();
225 $recreatetree = true;
229 grade_regrade_final_grades($courseid);
230 // Check to see if any weights were automatically adjusted.
231 // Run through the data to obtain all of the weight categories.
232 foreach ($data as $key => $notused) {
233 // We only want the weight entries.
234 if (preg_match('/^(weight)_([0-9]+)$/', $key, $matches)) {
235 // Fetch the weight for the grade item.
236 $gradeitemweight = grade_item
::fetch(array('id' => $matches[2], 'courseid' => $courseid))->aggregationcoef2
;
237 // Compare what was entered from the form with what was actually entered into the database.
238 if ($data->$matches[0] != ($gradeitemweight * 100)) {
239 // Send a notification that the weights were automatically adjusted.
240 $normalisationmessage = get_string('weightsadjusted', 'grades');
247 print_grade_page_head($courseid, 'settings', 'setup', get_string('setupgradeslayout', 'grades'));
249 // Print Table of categories and items
250 echo $OUTPUT->box_start('gradetreebox generalbox');
252 echo '<form id="gradetreeform" method="post" action="'.$returnurl.'">';
254 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
256 //did we update something in the db and thus invalidate $grade_edit_tree?
258 $grade_edit_tree = new grade_edit_tree($gtree, $movingeid, $gpr);
260 // Check to see if we have a normalisation message to send.
261 if (!empty($normalisationmessage)) {
262 echo $OUTPUT->notification($normalisationmessage, 'notifymessage');
265 echo html_writer
::table($grade_edit_tree->table
);
267 echo '<div id="gradetreesubmit">';
269 echo '<input class="advanced" type="submit" value="'.get_string('savechanges').'" />';
272 // We don't print a bulk move menu if there are no other categories than course category
273 if (!$moving && count($grade_edit_tree->categories
) > 1) {
275 echo '<input type="hidden" name="bulkmove" value="0" id="bulkmoveinput" />';
276 $attributes = array('id'=>'menumoveafter', 'class' => 'ignoredirty');
277 echo html_writer
::label(get_string('moveselectedto', 'grades'), 'menumoveafter');
278 echo html_writer
::select($grade_edit_tree->categories
, 'moveafter', '', array(''=>'choosedots'), $attributes);
279 $OUTPUT->add_action_handler(new component_action('change', 'submit_bulk_move'), 'menumoveafter');
280 echo '<div id="noscriptgradetreeform" class="hiddenifjs">
281 <input type="submit" value="'.get_string('go').'" />
287 echo '</div></form>';
289 echo $OUTPUT->box_end();
291 // Print action buttons
292 echo $OUTPUT->container_start('buttons mdl-align');
295 echo $OUTPUT->single_button(new moodle_url('index.php', array('id'=>$course->id
)), get_string('cancel'), 'get');
297 echo $OUTPUT->single_button(new moodle_url('category.php', array('courseid'=>$course->id
)), get_string('addcategory', 'grades'), 'get');
298 echo $OUTPUT->single_button(new moodle_url('item.php', array('courseid'=>$course->id
)), get_string('additem', 'grades'), 'get');
300 if (!empty($CFG->enableoutcomes
)) {
301 echo $OUTPUT->single_button(new moodle_url('outcomeitem.php', array('courseid'=>$course->id
)), get_string('addoutcomeitem', 'grades'), 'get');
304 //echo $OUTPUT->(new moodle_url('index.php', array('id'=>$course->id, 'action'=>'autosort')), get_string('autosort', 'grades'), 'get');
307 echo $OUTPUT->container_end();
309 $PAGE->requires
->yui_module('moodle-core-formchangechecker',
310 'M.core_formchangechecker.init',
312 'formid' => 'gradetreeform'
315 $PAGE->requires
->string_for_js('changesmadereallygoaway', 'moodle');
317 echo $OUTPUT->footer();