From 23207a1a6a890250f28645401940270a5bafc187 Mon Sep 17 00:00:00 2001 From: skodak Date: Sat, 21 Jul 2007 14:24:39 +0000 Subject: [PATCH] MDL-10563 item excluding implemented; improved/fixed grade edit page; some other improvements and cleanup --- backup/backuplib.php | 1 + backup/restorelib.php | 1 + grade/edit/grade.php | 148 +++++++++++++------------- grade/edit/grade_form.php | 64 ++++++++--- grade/report/grader/lib.php | 18 ++-- grade/report/user/lib.php | 16 +-- lang/en_utf8/grades.php | 4 +- lib/db/install.xml | 10 +- lib/db/upgrade.php | 61 +++++++---- lib/grade/grade_category.php | 23 ++-- lib/grade/grade_grade.php | 56 ++++++++++ lib/grade/grade_item.php | 19 ++++ lib/gradelib.php | 18 +++- lib/simpletest/fixtures/gradetest.php | 2 + version.php | 2 +- 15 files changed, 306 insertions(+), 137 deletions(-) diff --git a/backup/backuplib.php b/backup/backuplib.php index 115cb91685..9dede40211 100644 --- a/backup/backuplib.php +++ b/backup/backuplib.php @@ -1584,6 +1584,7 @@ fwrite ($bf,full_tag("LOCKTIME",7,false,$final->locktime)); fwrite ($bf,full_tag("EXPORTED",7,false,$final->exported)); fwrite ($bf,full_tag("OVERRIDDEN",7,false,$final->overridden)); + fwrite ($bf,full_tag("EXCLUDED",7,false,$final->excluded)); fwrite ($bf,end_tag("GRADE",6,true)); } $stauts = fwrite ($bf,end_tag("GRADE_GRADES",5,true)); diff --git a/backup/restorelib.php b/backup/restorelib.php index f25781d823..8d85723e60 100644 --- a/backup/restorelib.php +++ b/backup/restorelib.php @@ -1540,6 +1540,7 @@ $grade->locktime = backup_todb($ite_info['#']['LOCKTIME']['0']['#']); $grade->exported = backup_todb($ite_info['#']['EXPORTED']['0']['#']); $grade->overridden = backup_todb($ite_info['#']['OVERRIDDEN']['0']['#']); + $grade->excluded = backup_todb($ite_info['#']['EXCLUDED']['0']['#']); insert_record('grade_grades', $grade); diff --git a/grade/edit/grade.php b/grade/edit/grade.php index fc1cc54e3e..63d15ddd18 100644 --- a/grade/edit/grade.php +++ b/grade/edit/grade.php @@ -6,14 +6,16 @@ require_once $CFG->libdir.'/gradelib.php'; require_once 'grade_form.php'; $courseid = required_param('courseid', PARAM_INT); -$id = optional_param('id', 0, PARAM_INT); // grade_grade id -$action = optional_param('action', 'view', PARAM_ALPHA); +$id = optional_param('id', 0, PARAM_INT); +$itemid = optional_param('itemid', 0, PARAM_INT); +$userid = optional_param('userid', 0, PARAM_INT); if (!$course = get_record('course', 'id', $courseid)) { print_error('nocourseid'); } -// capabilities check +// TODO: fix capabilities check +// TODO: add proper check that grade is editable require_login($course); $context = get_context_instance(CONTEXT_COURSE, $course->id); require_capability('gradereport/grader:manage', $context); @@ -22,115 +24,111 @@ require_capability('gradereport/grader:manage', $context); $gpr = new grade_plugin_return(); $returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report.php?id='.$course->id); -// TODO: add proper check that grade is editable +// security checks! +if (!empty($id)) { + if (!$grade = get_record('grade_grades', 'id', $id)) { + error('Incorrect grade id'); + } + + if (!empty($itemid) and $itemid != $grade->itemid) { + error('Incorrect itemid'); + } + $itemid = $grade->itemid; + + if (!empty($userid) and $userid != $grade->userid) { + error('Incorrect userid'); + } + $userid = $grade->userid; -$grade_grade = get_record('grade_grades', 'id', $id); -$gradeitem = get_record('grade_items', 'id', $grade_grade->itemid); + unset($grade); -$mform = new edit_grade_form(null, array('gradeitem'=>$gradeitem, 'gpr'=>$gpr)); -if ($grade_grade = get_record('grade_grades', 'id', $id)) { - if ($grade_text = get_record('grade_grades_text', 'gradeid', $id)) { +} else if (empty($userid) or empty($itemid)) { + error('Missing userid and itemid'); +} + +if (!$grade_item = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$courseid))) { + error('Can not find grade_item'); +} + + +$mform = new edit_grade_form(null, array('grade_item'=>$grade_item, 'gpr'=>$gpr)); + +if ($grade = get_record('grade_grades', 'itemid', $id, 'userid', $userid)) { + if ($grade_text = get_record('grade_grades_text', 'gradeid', $grade->id)) { + // always clean existing feedback - grading should not have XSS risk if (can_use_html_editor()) { $options = new object(); - $options->smiley = false; - $options->filter = false; - $grade_text->feedback = format_text($grade_text->feedback, $grade_text->feedbackformat, $options); - $grade_text->feedbackformat = FORMAT_HTML; + $options->smiley = false; + $options->filter = false; + $options->noclean = false; + $grade->feedback = format_text($grade_text->feedback, $grade_text->feedbackformat, $options); + $grade->feedbackformat = FORMAT_HTML; + } else { + $grade->feedback = clean_text($grade_text->feedback, $grade_text->feedbackformat); + $grade->feedbackformat = $grade_text->feedbackformat; } - $mform->set_data($grade_text); } - $grade_grade->locked = $grade_grade->locked > 0 ? 1:0; - $grade_grade->courseid = $courseid; - $mform->set_data($grade_grade); + $grade->locked = $grade->locked > 0 ? 1:0; + $grade->overridden = $grade->overridden > 0 ? 1:0; + $grade->excluded = $grade->excluded > 0 ? 1:0; + + $mform->set_data($grade); } else { - $mform->set_data(array('courseid'=>$course->id, 'id' => $id)); + $mform->set_data(array('itemid'=>$itemid, 'userid'=>$userid)); } if ($mform->is_cancelled()) { redirect($returnurl); + // form processing } else if ($data = $mform->get_data()) { - $grade_grade = new grade_grade(array('id'=>$id)); - $grade_item = new grade_item(array('id'=>$grade_grade->itemid)); - $grade_item->update_final_grade($grade_grade->userid, $data->finalgrade, NULL, NULL, $data->feedback, $data->feedbackformat); + $old_grade_grade = new grade_grade(array('userid'=>$data->userid, 'itemid'=>$grade_item->id), true); //might not exist yet - // Assign finalgrade value - $grade_grade->finalgrade = $data->finalgrade; + // update final grade or feedback + $grade_item->update_final_grade($data->userid, $data->finalgrade, NULL, 'editgrade', $data->feedback, $data->feedbackformat); - // set locked - $grade_grade->set_locked($data->locked); + $grade_grade = grade_grade::fetch(array('userid'=>$data->userid, 'itemid'=>$grade_item->id)); - // set hidden - $grade_grade->set_hidden($data->hidden); + $grade_grade->set_hidden($data->hidden); // TODO: this is wrong! + + // ignore overridden flag when changing final grade + if ($old_grade_grade->finalgrade == $grade_grade->finalgrade) { + if ($grade_grade->set_overridden($data->overridden) and empty($data->overridden)) { + $grade_item->force_regrading(); // force regrading only when clearing the flag + } + } + + if ($grade_grade->set_excluded($data->excluded)) { + $grade_item->force_regrading(); + } - // set locktime + $grade_grade->set_locked($data->locked); $grade_grade->set_locktime($data->locktime); redirect($returnurl); } -// Get extra data related to this feedback -$query = "SELECT a.id AS userid, a.firstname, a.lastname, - b.id AS itemid, b.itemname, b.grademin, b.grademax, b.iteminstance, b.itemmodule, b.scaleid, - c.finalgrade - FROM {$CFG->prefix}user a, - {$CFG->prefix}grade_items b, - {$CFG->prefix}grade_grades c - WHERE c.id = $id - AND b.id = c.itemid - AND a.id = c.userid"; - -$extra_info = get_record_sql($query) ; -$extra_info->grademin = round($extra_info->grademin); -$extra_info->grademax = round($extra_info->grademax); -$extra_info->finalgrade = round($extra_info->finalgrade); - -if (!empty($extra_info->itemmodule) && !empty($extra_info->iteminstance)) { - $extra_info->course_module = get_coursemodule_from_instance($extra_info->itemmodule, $extra_info->iteminstance, $courseid); -} - -$stronascaleof = get_string('onascaleof', 'grades', $extra_info); $strgrades = get_string('grades'); -$strgrade = get_string('grade'); $strgraderreport = get_string('graderreport', 'grades'); -$strgrade = get_string('grade', 'grades'); -$strgradeedit = get_string('gradeedit', 'grades'); -$strgradeview = get_string('gradeview', 'grades'); -$strstudent = get_string('student', 'grades'); -$strgradeitem = get_string('gradeitem', 'grades'); - -$feedback = null; -$heading = ${"strgrade$action"}; -if (!empty($action) && $action == 'view' && !empty($grade_text->feedback)) { - $feedback = "

$strgrade:

$grade_text->feedback

"; -} +$strgradeedit = get_string('editgrade', 'grades'); +$struser = get_string('user'); $nav = array(array('name'=>$strgrades,'link'=>$CFG->wwwroot.'/grade/index.php?id='.$courseid, 'type'=>'misc'), - array('name'=>$heading, 'link'=>'', 'type'=>'misc')); + array('name'=>$strgradeedit, 'link'=>'', 'type'=>'misc')); $navigation = build_navigation($nav); /*********** BEGIN OUTPUT *************/ -print_header_simple($strgrades . ': ' . $strgraderreport . ': ' . $heading, - ': ' . $heading , $navigation, '', '', true, '', navmenu($course)); +print_header_simple($strgrades . ': ' . $strgraderreport . ': ' . $strgradeedit, + ': ' . $strgradeedit , $navigation, '', '', true, '', navmenu($course)); -print_heading($heading); +print_heading($strgradeedit); print_simple_box_start("center"); -// Student name and link -echo "

$strstudent: wwwroot . '/user/view.php?id=' - . $extra_info->userid . '">' . fullname($extra_info) . "

"; - -// Grade item name and link -if (!empty($extra_info->course_module) && !empty($extra_info->itemmodule)) { - echo "

$strgradeitem: wwwroot . '/mod/' . $extra_info->itemmodule - . '/view.php?id=' . $extra_info->course_module->id . "&courseid=$courseid\">$extra_info->itemname

"; -} - // Form if in edit or add modes $mform->display(); diff --git a/grade/edit/grade_form.php b/grade/edit/grade_form.php index e04af01e25..ad6c133867 100755 --- a/grade/edit/grade_form.php +++ b/grade/edit/grade_form.php @@ -3,24 +3,31 @@ require_once $CFG->libdir.'/formslib.php'; class edit_grade_form extends moodleform { + function definition() { + global $CFG, $COURSE; - global $CFG, $USER; $mform =& $this->_form; - $gradeitem = $this->_customdata['gradeitem']; + $grade_item = $this->_customdata['grade_item']; + $gpr = $this->_customdata['gpr']; + + /// information fields + $mform->addElement('static', 'user', get_string('user')); + $mform->addElement('static', 'itemname', get_string('itemname', 'grades')); - /// actual grade - numeric or scale - if ($gradeitem->gradetype == GRADE_TYPE_VALUE) { + /// actual grade - numeric or scale + if ($grade_item->gradetype == GRADE_TYPE_VALUE) { // numeric grade $mform->addElement('text', 'finalgrade', get_string('finalgrade', 'grades')); - } else if ($gradeitem->gradetype == GRADE_TYPE_SCALE) { + } else if ($grade_item->gradetype == GRADE_TYPE_SCALE) { // scale grade + $scaleopt = array(); $scaleopt[-1] = get_string('nograde'); $i = 1; - if ($scale = get_record('scale', 'id', $gradeitem->scaleid)) { + if ($scale = get_record('scale', 'id', $grade_item->scaleid)) { foreach (split(",", $scale->scale) as $option) { $scaleopt[$i] = $option; $i++; @@ -30,38 +37,65 @@ class edit_grade_form extends moodleform { $mform->addElement('select', 'finalgrade', get_string('finalgrade', 'grades'), $scaleopt); } - /// hidden $mform->addElement('advcheckbox', 'hidden', get_string('hidden', 'grades')); + $mform->addElement('advcheckbox', 'overridden', get_string('overridden', 'grades')); + $mform->addElement('advcheckbox', 'excluded', get_string('excluded', 'grades')); - /// locked + /// locking $mform->addElement('advcheckbox', 'locked', get_string('locked', 'grades')); - - /// locktime $mform->addElement('date_time_selector', 'locktime', get_string('locktime', 'grades'), array('optional'=>true)); $mform->disabledIf('locktime', 'gradetype', 'eq', GRADE_TYPE_NONE); // Feedback format is automatically converted to html if user has enabled editor $mform->addElement('htmleditor', 'feedback', get_string('feedback', 'grades'), - array('rows'=> '15', 'course' => $gradeitem->courseid, 'cols'=>'45')); - $mform->setType('text', PARAM_RAW); // to be cleaned before display + array('rows'=>'15', 'course'=>$COURSE->id, 'cols'=>'45')); + $mform->setType('text', PARAM_RAW); // to be cleaned before display, no XSS risk $mform->addElement('format', 'feedbackformat', get_string('format')); $mform->setHelpButton('feedbackformat', array('textformat', get_string('helpformatting'))); // hidden params $mform->addElement('hidden', 'id', 0); - $mform->setType('gradeid', PARAM_INT); + $mform->setType('id', PARAM_INT); + + $mform->addElement('hidden', 'itemid', 0); + $mform->setType('itemid', PARAM_INT); - $mform->addElement('hidden', 'courseid', 0); + $mform->addElement('hidden', 'userid', 0); + $mform->setType('userid', PARAM_INT); + + $mform->addElement('hidden', 'courseid', $COURSE->id); $mform->setType('courseid', PARAM_INT); /// add return tracking info - $gpr = $this->_customdata['gpr']; $gpr->add_mform_elements($mform); //------------------------------------------------------------------------------- // buttons $this->add_action_buttons(); } + + function definition_after_data() { + global $CFG; + + $mform =& $this->_form; + $grade_item = $this->_customdata['grade_item']; + + if ($userid = $mform->getElementValue('userid')) { + $user = get_record('user', 'id', $userid); + $username = ''.fullname($user).''; + $user_el =& $mform->getElement('user'); + $user_el->setValue($username); + } + + if ($grade_item->itemtype == 'mod') { + $cm = get_coursemodule_from_instance($grade_item->itemmodule, $grade_item->iteminstance, $grade_item->courseid); + $itemname = ''.$grade_item->get_name().''; + } else { + $itemname = $grade_item->get_name(); + } + $itemname_el =& $mform->getElement('itemname'); + $itemname_el->setValue($itemname); + } } ?> \ No newline at end of file diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php index b0dede1fad..7862ae6dbb 100644 --- a/grade/report/grader/lib.php +++ b/grade/report/grader/lib.php @@ -263,14 +263,12 @@ class grade_report_grader extends grade_report { function load_final_grades() { global $CFG; - $sql = "SELECT g.id, g.itemid, g.userid, g.finalgrade, g.hidden, g.locked, g.locktime, g.overridden, - gt.feedback, gt.feedbackformat, - gi.grademin, gi.grademax - FROM {$CFG->prefix}grade_items gi, - {$CFG->prefix}grade_grades g - LEFT JOIN {$CFG->prefix}grade_grades_text gt ON g.id = gt.gradeid - WHERE g.itemid = gi.id - AND gi.courseid = $this->courseid $this->userselect"; + // please note that we must fetch all grade_grades fields if we want to contruct grade_grade object from it! + $sql = "SELECT g.*, gt.feedback, gt.feedbackformat, gi.grademin, gi.grademax + FROM {$CFG->prefix}grade_items gi, + {$CFG->prefix}grade_grades g + LEFT JOIN {$CFG->prefix}grade_grades_text gt ON g.id = gt.gradeid + WHERE g.itemid = gi.id AND gi.courseid = $this->courseid $this->userselect"; if ($grades = get_records_sql($sql)) { foreach ($grades as $grade) { @@ -549,6 +547,10 @@ class grade_report_grader extends grade_report { $studentshtml .= ''; } + if ($grade->is_excluded()) { + $studentshtml .= get_string('excluded', 'grades'); // TODO: improve visual representation of excluded grades + } + // emulate grade element $grade->courseid = $this->courseid; $grade->grade_item = $item; // this may speedup is_hidden() and other grade_grade methods diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php index 3d5fc38dd2..20051681ec 100644 --- a/grade/report/user/lib.php +++ b/grade/report/user/lib.php @@ -110,9 +110,7 @@ class grade_report_user extends grade_report { $data = array(); - $params->itemid = $grade_item->id; - $params->userid = $this->user->id; - $grade_grade = new grade_grade($params); + $grade_grade = new grade_grade(array('itemid'=>$grade_item->id, 'userid'=>$this->user->id)); $grade_text = $grade_grade->load_text(); /// prints mod icon if available @@ -137,6 +135,12 @@ class grade_report_user extends grade_report { /// prints the grade + if ($grade_grade->is_excluded()) { + $excluded = get_tring('excluded', 'grades').' '; + } else { + $excluded = ''; + } + if ($grade_item->scaleid) { // using scales if ($scale = get_record('scale', 'id', $grade_item->scaleid)) { @@ -144,14 +148,14 @@ class grade_report_user extends grade_report { // reindex because scale is off 1 // invalid grade if gradeval < 1 if ((int) $grade_grade->finalgrade < 1) { - $data[] = '-'; + $data[] = $excluded.'-'; } else { - $data[] = $scales[$grade_grade->finalgrade-1]; + $data[] = $excluded.$scales[$grade_grade->finalgrade-1]; } } } else { // normal grade, or text, just display - $data[] = $this->get_grade_clean($grade_grade->finalgrade); + $data[] = $excluded.$this->get_grade_clean($grade_grade->finalgrade); } /// prints percentage diff --git a/lang/en_utf8/grades.php b/lang/en_utf8/grades.php index a3bba880ea..0e77c82de3 100644 --- a/lang/en_utf8/grades.php +++ b/lang/en_utf8/grades.php @@ -85,8 +85,9 @@ $string['droplow'] = 'Drop the lowest'; $string['dropped'] = 'Dropped'; $string['dropxlowest'] = 'Drop X Lowest'; $string['dropxlowestwarning'] = 'Note: If you use drop x lowest the grading assumes that all items in the category have the same point value. If point values differ results will be unpredictable'; -$string['editcalculation'] = 'Edit calculation'; +$string['editcalculation'] = 'Edit Calculation'; $string['editfeedback'] = 'Edit Feedback'; +$string['editgrade'] = 'Edit Grade'; $string['edittree'] = 'Categories'; $string['enableajax'] = 'Enable AJAX'; $string['encoding'] = 'Encoding'; @@ -215,6 +216,7 @@ $string['noselecteditems'] = 'no items were selected.'; $string['notteachererror'] = 'You must be a teacher to use this feature.'; $string['onascaleof'] = ' on a scale of $a->grademin to $a->grademax'; $string['outcome'] = 'Outcome'; +$string['overridden'] = 'Overridden'; $string['pctoftotalgrade'] = '%% of total grade'; $string['percent'] = 'Percent'; $string['percentage'] = 'Percentage'; diff --git a/lib/db/install.xml b/lib/db/install.xml index cbefe57565..2e906c388b 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -1,5 +1,5 @@ - @@ -1365,8 +1365,9 @@ - - + + + @@ -1513,7 +1514,8 @@ - + + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 2c8f75bdb9..7c636cf2ea 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -1017,6 +1017,7 @@ function xmldb_main_upgrade($oldversion=0) { $table->addFieldInfo('locktime', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('exported', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('overridden', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); + $table->addFieldInfo('excluded', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('timecreated', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null); $table->addFieldInfo('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null); @@ -1213,6 +1214,7 @@ function xmldb_main_upgrade($oldversion=0) { $table->addFieldInfo('locktime', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('exported', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('overridden', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); + $table->addFieldInfo('excluded', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); /// Adding keys to table grade_grades_history $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id')); @@ -1345,24 +1347,6 @@ function xmldb_main_upgrade($oldversion=0) { } if ($result && $oldversion < 2007071000) { - /// Remove obsoleted unitt tests tables - they will be recreated automatically - $tables = array('grade_categories', - 'scale', - 'grade_items', - 'grade_calculations', - 'grade_grades', - 'grade_grades_raw', - 'grade_grades_final', - 'grade_grades_text', - 'grade_outcomes', - 'grade_history'); - - foreach ($tables as $table) { - $table = new XMLDBTable('unittest_'.$table); - if (table_exists($table)) { - drop_table($table); - } - } /// Define field overridden to be added to grade_grades $table = new XMLDBTable('grade_grades'); @@ -1541,6 +1525,47 @@ function xmldb_main_upgrade($oldversion=0) { $result = $result && create_table($table); } + if ($result && $oldversion < 2007072100) { + /// Remove obsoleted unit tests tables - they will be recreated automatically + $tables = array('grade_categories', + 'scale', + 'grade_items', + 'grade_calculations', + 'grade_grades', + 'grade_grades_raw', + 'grade_grades_final', + 'grade_grades_text', + 'grade_outcomes', + 'grade_history'); + + foreach ($tables as $table) { + $table = new XMLDBTable('unittest_'.$table); + if (table_exists($table)) { + drop_table($table); + } + } + + /// Define field excluded to be added to grade_grades + $table = new XMLDBTable('grade_grades'); + $field = new XMLDBField('excluded'); + $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'overridden'); + + /// Launch add field excluded + if (!field_exists($table, $field)) { + $result = $result && add_field($table, $field); + } + + /// Define field excluded to be added to grade_grades + $table = new XMLDBTable('grade_grades_history'); + $field = new XMLDBField('excluded'); + $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'overridden'); + + /// Launch add field excluded + if (!field_exists($table, $field)) { + $result = $result && add_field($table, $field); + } + } + return $result; } ?> diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php index 80b096bf48..a3276c3e21 100644 --- a/lib/grade/grade_category.php +++ b/lib/grade/grade_category.php @@ -357,20 +357,25 @@ class grade_category extends grade_object { if ($rs->RecordCount() > 0) { $prevuser = 0; $grade_values = array(); + $excluded = array(); $oldgrade = null; while ($used = rs_fetch_next_record($rs)) { if ($used->userid != $prevuser) { - $this->aggregate_grades($prevuser, $items, $grade_values, $oldgrade); + $this->aggregate_grades($prevuser, $items, $grade_values, $oldgrade, $excluded); $prevuser = $used->userid; $grade_values = array(); + $excluded = array(); $oldgrade = null; } $grade_values[$used->itemid] = $used->finalgrade; + if ($used->excluded) { + $excluded[] = $used->itemid; + } if ($this->grade_item->id == $used->itemid) { $oldgrade = $used; } } - $this->aggregate_grades($prevuser, $items, $grade_values, $oldgrade);//the last one + $this->aggregate_grades($prevuser, $items, $grade_values, $oldgrade, $excluded);//the last one } } @@ -380,7 +385,7 @@ class grade_category extends grade_object { /** * internal function for category grades aggregation */ - function aggregate_grades($userid, $items, $grade_values, $oldgrade) { + function aggregate_grades($userid, $items, $grade_values, $oldgrade, $excluded) { if (empty($userid)) { //ignore first call return; @@ -424,13 +429,17 @@ class grade_category extends grade_object { /// normalize the grades first - all will have value 0...1 // ungraded items are not used in aggregation - foreach ($grade_values as $k=>$v) { + foreach ($grade_values as $itemid=>$v) { if (is_null($v)) { // null means no grade - unset($grade_values[$k]); + unset($grade_values[$itemid]); + continue; + } else if (in_array($itemid, $excluded)) { + unset($grade_values[$itemid]); continue; } - $grade_values[$k] = grade_grade::standardise_score($v, $items[$k]->grademin, $items[$k]->grademax, 0, 1); + + $grade_values[$itemid] = grade_grade::standardise_score($v, $items[$itemid]->grademin, $items[$itemid]->grademax, 0, 1); } // use min grade if grade missing for these types @@ -443,7 +452,7 @@ class grade_category extends grade_object { case GRADE_AGGREGATE_WEIGHTED_MEAN_ALL: case GRADE_AGGREGATE_EXTRACREDIT_MEAN_ALL: foreach($items as $itemid=>$value) { - if (!isset($grade_values[$itemid])) { + if (!isset($grade_values[$itemid]) and !in_array($itemid, $excluded)) { $grade_values[$itemid] = 0; } } diff --git a/lib/grade/grade_grade.php b/lib/grade/grade_grade.php index eb070d2813..b73c294a8c 100644 --- a/lib/grade/grade_grade.php +++ b/lib/grade/grade_grade.php @@ -131,6 +131,12 @@ class grade_grade extends grade_object { */ var $overridden = 0; + /** + * Grade excluded from aggregation functions + * @var boolean $excluded + */ + var $excluded = 0; + /** * Loads the grade_grade_text object linked to this grade (through the intersection of itemid and userid), and * saves it as a class variable for this final object. @@ -195,10 +201,60 @@ class grade_grade extends grade_object { return !empty($this->locked) or $this->grade_item->is_locked(); } + /** + * Checks if grade overridden + * @return boolean + */ function is_overridden() { return !empty($this->overridden); } + /** + * Set the overridden status of grade + * @param boolean $state requested overridden state + * @return boolean true is db state changed + */ + function set_overridden($state) { + if (empty($this->overridden) and $state) { + $this->overridden = time(); + $this->update(); + return true; + + } else if (!empty($this->overridden) and !$state) { + $this->overridden = 0; + $this->update(); + return true; + } + return false; + } + + /** + * Checks if grade excluded from aggregation functions + * @return boolean + */ + function is_excluded() { + return !empty($this->excluded); + } + + /** + * Set the excluded status of grade + * @param boolean $state requested excluded state + * @return boolean true is db state changed + */ + function set_excluded($state) { + if (empty($this->excluded) and $state) { + $this->excluded = time(); + $this->update(); + return true; + + } else if (!empty($this->excluded) and !$state) { + $this->excluded = 0; + $this->update(); + return true; + } + return false; + } + /** * Lock/unlock this grade. * diff --git a/lib/grade/grade_item.php b/lib/grade/grade_item.php index 4a15d22b95..0a5914ed6a 100644 --- a/lib/grade/grade_item.php +++ b/lib/grade/grade_item.php @@ -982,6 +982,25 @@ class grade_item extends grade_object { } } + /** + * Get (or create if not exist yet) grade for this user + * @param int $userid + * @return object grade_grade object instance + */ + function get_grade($userid) { + if (empty($this->id)) { + debugging('Can not use before insert'); + return false; + } + + $grade = new grade_grade(array('userid'=>$userid, 'itemid'=>$this->id)); + if (empty($grade->id)) { + $grade->insert(); + } + + return $grade; + } + /** * Returns the sortorder of this grade_item. This method is also available in * grade_category, for cases where the object type is not know. diff --git a/lib/gradelib.php b/lib/gradelib.php index 3e4b6dfbea..50b4b8e315 100644 --- a/lib/gradelib.php +++ b/lib/gradelib.php @@ -668,7 +668,7 @@ function grade_get_legacy_grade_item($modinstance, $grademax, $scaleid) { } /** - * This function is used to migrade old date and settings from old gradebook into new grading system. + * This function is used to migrade old data and settings from old gradebook into new grading system. * @param int $courseid */ function grade_upgrade_oldgradebook($courseid) { @@ -719,6 +719,8 @@ function grade_upgrade_oldgradebook($courseid) { $course_category->update('upgrade'); } + + $newitems = array(); // get all grade items with mod details $sql = "SELECT gi.*, cm.idnumber as cmidnumber, m.name as modname FROM {$CFG->prefix}grade_item gi, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m @@ -745,10 +747,22 @@ function grade_upgrade_oldgradebook($courseid) { if (!empty($olditem->category)) { $newitem->set_parent($categories[$olditem->category]->id); } + $newitems[$olditem->id] = $newitem; } } - // setup up exception handling + // setup up exception handling - override grade with NULL + if ($exceptions = get_records('grade_exceptions', 'courseid', $courseid)) { + foreach ($exceptions as $exception) { + if (!array_key_exists($exception->grade_itemid, $newitems)) { + continue; // broken record + } + $grade_item = grade_item::fetch(array('id'=>$newitems[$exception->grade_itemid])); + $grade = $grade_item->get_grade($exception->userid); + $grade->excluded = time(); + $grade->update(); + } + } } /** diff --git a/lib/simpletest/fixtures/gradetest.php b/lib/simpletest/fixtures/gradetest.php index 8fa4448f01..2860e20a59 100644 --- a/lib/simpletest/fixtures/gradetest.php +++ b/lib/simpletest/fixtures/gradetest.php @@ -188,6 +188,7 @@ class grade_test extends UnitTestCase { $table->addFieldInfo('locktime', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('exported', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('overridden', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); + $table->addFieldInfo('excluded', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('timecreated', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null); $table->addFieldInfo('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null); @@ -410,6 +411,7 @@ class grade_test extends UnitTestCase { $table->addFieldInfo('locktime', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('exported', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); $table->addFieldInfo('overridden', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); + $table->addFieldInfo('excluded', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0'); /// Adding keys to table grade_grades_history $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id')); diff --git a/version.php b/version.php index 219960f297..e0255015de 100644 --- a/version.php +++ b/version.php @@ -6,7 +6,7 @@ // This is compared against the values stored in the database to determine // whether upgrades should be performed (see lib/db/*.php) - $version = 2007071900; // YYYYMMDD = date + $version = 2007072100; // YYYYMMDD = date // XY = increments within a single day $release = '1.9 dev'; // Human-friendly version name -- 2.39.5