]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-10563 item excluding implemented;
authorskodak <skodak>
Sat, 21 Jul 2007 14:24:39 +0000 (14:24 +0000)
committerskodak <skodak>
Sat, 21 Jul 2007 14:24:39 +0000 (14:24 +0000)
improved/fixed grade edit page;
some other improvements and cleanup

15 files changed:
backup/backuplib.php
backup/restorelib.php
grade/edit/grade.php
grade/edit/grade_form.php
grade/report/grader/lib.php
grade/report/user/lib.php
lang/en_utf8/grades.php
lib/db/install.xml
lib/db/upgrade.php
lib/grade/grade_category.php
lib/grade/grade_grade.php
lib/grade/grade_item.php
lib/gradelib.php
lib/simpletest/fixtures/gradetest.php
version.php

index 115cb916857096020ed95ec23080a8721d6c3da7..9dede40211de8cfe82107ee71a6cc67ec31c4265 100644 (file)
                 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));
index f25781d823e365a0e786c4d9a7d7acea3b33eb89..8d85723e601127cd26a603195af161a3d6e942ac 100644 (file)
                                     $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);
                                     
index fc1cc54e3e2ff4a968704dce735d9ce904bad927..63d15ddd1883d607ee758dbcb99516c5cc9e63a7 100644 (file)
@@ -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 = "<p><strong>$strgrade</strong>:</p><p>$grade_text->feedback</p>";
-}
+$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 "<p><strong>$strstudent:</strong> <a href=\"" . $CFG->wwwroot . '/user/view.php?id='
-     . $extra_info->userid . '">' . fullname($extra_info) . "</a></p>";
-
-// Grade item name and link
-if (!empty($extra_info->course_module) && !empty($extra_info->itemmodule)) {
-    echo "<p><strong>$strgradeitem:</strong> <a href=\"" . $CFG->wwwroot . '/mod/' . $extra_info->itemmodule
-         . '/view.php?id=' . $extra_info->course_module->id . "&amp;courseid=$courseid\">$extra_info->itemname</a></p>";
-}
-
 // Form if in edit or add modes
 $mform->display();
 
index e04af01e25b5611a7cb0801be09992bffd152bce..ad6c1338670b4a3542cbed9fcc813ba0e3c1aa79 100755 (executable)
@@ -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 = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$userid.'">'.fullname($user).'</a>';
+            $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 = '<a href="'.$CFG->wwwroot.'/mod/'.$grade_item->itemmodule.'/view.php?id='.$cm->id.'">'.$grade_item->get_name().'</a>';
+        } else {
+            $itemname = $grade_item->get_name();
+        }
+        $itemname_el =& $mform->getElement('itemname');
+        $itemname_el->setValue($itemname);
+    }
 }
 
 ?>
\ No newline at end of file
index b0dede1fad6354c39c17b9b63547c1b1fe06fe64..7862ae6dbb78dd37903a429eee51d16c809fc331 100644 (file)
@@ -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 .= '<td>';
                 }
 
+                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
index 3d5fc38dd2e2f1fac30a6fb9677bef9142f4caab..20051681ec63e16c6dc3f4f0b1dbeeeab5929e82 100644 (file)
@@ -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
index a3bba880ea5e4409074a104b151dbc75fe662127..0e77c82de3bff5c005ab78cdd2a9a2d9557d9d7f 100644 (file)
@@ -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';
index cbefe575657e4f09686409147577d357840a09f4..2e906c388b3481cb9b9a80d447b4c54e40211b11 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="lib/db" VERSION="20070719" COMMENT="XMLDB file for core Moodle tables"
+<XMLDB PATH="lib/db" VERSION="20070721" COMMENT="XMLDB file for core Moodle tables"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
 >
         <FIELD NAME="locked" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="not locked 0, locked from date" PREVIOUS="hidden" NEXT="locktime"/>
         <FIELD NAME="locktime" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="automatic locking of final grade, 0 means none, date otherwise" PREVIOUS="locked" NEXT="exported"/>
         <FIELD NAME="exported" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="date of last grade export, 0 if none" PREVIOUS="locktime" NEXT="overridden"/>
-        <FIELD NAME="overridden" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="indicates grade overridden from gradebook, 0 means none, date means overridden" PREVIOUS="exported" NEXT="timecreated"/>
-        <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="the time this grade was first created" PREVIOUS="overridden" NEXT="timemodified"/>
+        <FIELD NAME="overridden" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="indicates grade overridden from gradebook, 0 means none, date means overridden" PREVIOUS="exported" NEXT="excluded"/>
+        <FIELD NAME="excluded" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="grade excluded from aggregation functions, date means when excluded" PREVIOUS="overridden" NEXT="timecreated"/>
+        <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="the time this grade was first created" PREVIOUS="excluded" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="the time this grade was last modified" PREVIOUS="timecreated"/>
       </FIELDS>
       <KEYS>
         <FIELD NAME="locked" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="not locked 0, locked from date" PREVIOUS="hidden" NEXT="locktime"/>
         <FIELD NAME="locktime" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="automatic locking of final grade, 0 means none, date otherwise" PREVIOUS="locked" NEXT="exported"/>
         <FIELD NAME="exported" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="date of last grade export, 0 if none" PREVIOUS="locktime" NEXT="overridden"/>
-        <FIELD NAME="overridden" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="indicates grade overridden from gradebook, 0 means none, date means overridden" PREVIOUS="exported"/>
+        <FIELD NAME="overridden" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="indicates grade overridden from gradebook, 0 means none, date means overridden" PREVIOUS="exported" NEXT="excluded"/>
+        <FIELD NAME="excluded" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="grade excluded from aggregation functions, date means when excluded" PREVIOUS="overridden"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="primary key of the table, please edit me" NEXT="oldid"/>
index 2c8f75bdb9cacb40394e63125fa34b1dd27381a0..7c636cf2ea354cedbcd75fab56b625ca1676cd9d 100644 (file)
@@ -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;
 }
 ?>
index 80b096bf487729425b94026abf7c5b8bfac0dcad..a3276c3e212211753e6477db07b27631a860a752 100644 (file)
@@ -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;
                     }
                 }
index eb070d28135c580813e84ae073b7f3f05542f523..b73c294a8c4de651cd8bca90550d787980f0a264 100644 (file)
@@ -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.
      *
index 4a15d22b957a1ca3a0783256edf11ee867746cb1..0a5914ed6a93a1c71d87c66d9bb5f91660fdcecc 100644 (file)
@@ -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.
index 3e4b6dfbea1f5ba41f3e348b08ce8088561228ad..50b4b8e31525620722e31d692eb0b837b8e83539 100644 (file)
@@ -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();
+        }
+    }
 }
 
 /**
index 8fa4448f018ebd130c4227604d8518d0e7c064b7..2860e20a59e0d3868d27393e8065129c1c48aaea 100644 (file)
@@ -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'));
index 219960f297566634c86319ea561e84639f768ce6..e0255015de15c7a848f0f9f72db3dcb121391224 100644 (file)
@@ -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