]> git.mjollnir.org Git - moodle.git/commitdiff
various locking improvements and fixes, cron locktime support stilll missing
authorskodak <skodak>
Thu, 9 Aug 2007 09:03:14 +0000 (09:03 +0000)
committerskodak <skodak>
Thu, 9 Aug 2007 09:03:14 +0000 (09:03 +0000)
grade/edit/tree/action.php
grade/edit/tree/grade.php
grade/edit/tree/grade_form.php
grade/edit/tree/item.php
grade/edit/tree/outcomeitem.php
grade/lib.php
lang/en_utf8/grades.php
lib/grade/grade_category.php
lib/grade/grade_grade.php
lib/grade/grade_item.php
lib/gradelib.php

index b7b83e0aa7e9c4d2918c5a73886c9019f84d9524..a239781d8780fa409515619aa26def5bb5c18906 100644 (file)
@@ -62,7 +62,7 @@ switch ($action) {
             if ($type == 'grade' and empty($object->id)) {
                 $object->insert();
             }
-            $object->set_locked(1);
+            $object->set_locked(1, true, true);
         }
         break;
 
@@ -74,7 +74,7 @@ switch ($action) {
             if ($type == 'grade' and empty($object->id)) {
                 $object->insert();
             }
-            $object->set_locked(0);
+            $object->set_locked(0, true, true);
         }
         break;
 }
index 3a0b01753fe27f5d17c8e815e4794159504a99cb..8e5bb5f48a37fcdec1df93ea558ad75a02db4d19 100644 (file)
@@ -95,6 +95,10 @@ if ($grade = get_record('grade_grades', 'itemid', $grade_item->id, 'userid', $us
         $grade->hiddenuntil = 0;
     }
 
+    if ($grade_item->is_locked()) {
+        $grade->locked = 1;
+    }
+
     $mform->set_data($grade);
 
 } else {
@@ -109,14 +113,22 @@ if ($mform->is_cancelled()) {
     $old_grade_grade = new grade_grade(array('userid'=>$data->userid, 'itemid'=>$grade_item->id), true); //might not exist yet
 
     // fix no grade for scales
-    if ($grade_item->gradetype == GRADE_TYPE_SCALE and $data->finalgrade < 1) {
+    if (!isset($data->finalgrade)) {
+        $data->finalgrade = $old_grade_grade->finalgrade;
+
+    } else if ($grade_item->gradetype == GRADE_TYPE_SCALE and $data->finalgrade < 1) {
         $data->finalgrade = NULL;
     }
 
+    if (!isset($data->feedback)) {
+        $data->feedback       = $old_grade_grade->feedback;
+        $data->feedbackformat = $old_grade_grade->feedbackformat;
+    }
     // update final grade or feedback
     $grade_item->update_final_grade($data->userid, $data->finalgrade, NULL, 'editgrade', $data->feedback, $data->feedbackformat);
 
     $grade_grade = grade_grade::fetch(array('userid'=>$data->userid, 'itemid'=>$grade_item->id));
+    $grade_grade->grade_item =& $grade_item; // no db fetching
 
     if (has_capability('moodle/grade:manage', $context) or has_capability('moodle/grade:hide', $context)) {
         if (empty($data->hidden)) {
@@ -130,33 +142,43 @@ if ($mform->is_cancelled()) {
         }
     }
 
-    if (has_capability('moodle/grade:manage', $context) or has_capability('moodle/grade:override', $context)) {
-        // 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 (isset($data->locked) and !$grade_item->is_locked()) {
+        if (($old_grade_grade->locked or $old_grade_grade->locktime)
+          and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:unlock', $context))) {
+            //ignore data
+
+        } else if ((!$old_grade_grade->locked and !$old_grade_grade->locktime)
+          and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:lock', $context))) {
+            //ignore data
+
+        } else {
+            $grade_grade->set_locktime($data->locktime); //set_lock may reset locktime
+            $grade_grade->set_locked($data->locked, false, true);
         }
     }
 
-    if (has_capability('moodle/grade:manage', $context)) {
-        if ($grade_grade->set_excluded($data->excluded)) {
-            $grade_item->force_regrading();
+    if (isset($data->excluded) and has_capability('moodle/grade:manage', $context)) {
+        $grade_grade->set_excluded($data->excluded);
+    }
+
+    if (isset($data->overridden) and has_capability('moodle/grade:manage', $context) or has_capability('moodle/grade:override', $context)) {
+        // ignore overridden flag when changing final grade
+        if ($old_grade_grade->finalgrade == $grade_grade->finalgrade) {
+            $grade_grade->set_overridden($data->overridden);
         }
     }
 
-    if (($old_grade_grade->locked or $old_grade_grade->locktime)
-      and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:unlock', $context))) {
-        //ignore data
+    // detect cases when we need to do full regrading
+    if ($old_grade_grade->excluded != $grade_grade->excluded) {
+        $parent = $grade_item->get_parent_category();
+        $parent->force_regrading();
 
-    } else if ((!$old_grade_grade->locked and !$old_grade_grade->locktime)
-      and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:lock', $context))) {
-        //ignore data
+    } else if ($old_grade_grade->overridden != $grade_grade->overridden and empty($grade_grade->overridden)) { // only when unoverriding
+        $grade_item->force_regrading();
 
-    } else {
-        $grade_grade->set_locked($data->locked);
-        $grade_grade->set_locktime($data->locktime);
-      }
+    } else if ($old_grade_grade->locktime != $grade_grade->locktime) {
+        $grade_item->force_regrading();
+    }
 
     redirect($returnurl);
 }
index 40c679517c18857b067050e1792b912517486e7f..2a87ce8ac06e87858a0bf3827d9384c138c6018e 100755 (executable)
@@ -135,20 +135,33 @@ class edit_grade_form extends moodleform {
         }
 
         $old_grade_grade = new grade_grade(array('itemid'=>$grade_item->id, 'userid'=>$userid));
-        if (empty($old_grade_grade->id)) {
-            $old_grade_grade->locked = $grade_item->locked;
-            $old_grade_grade->locktime = $grade_item->locktime;
-        }
 
-        if (($old_grade_grade->locked or $old_grade_grade->locktime)
-          and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:unlock', $context))) {
-            $mform->hardFreeze('locked');
-            $mform->hardFreeze('locktime');
+        if ($old_grade_grade->is_locked()) {
+            if ($grade_item->is_locked()) {
+                $mform->hardFreeze('locked');
+                $mform->hardFreeze('locktime');
+            }
+
+            $mform->hardFreeze('overridden');
+            $mform->hardFreeze('finalgrade');
+            $mform->hardFreeze('feedback');
+
+        } else {
+            if (empty($old_grade_grade->id)) {
+                $old_grade_grade->locked = $grade_item->locked;
+                $old_grade_grade->locktime = $grade_item->locktime;
+            }
 
-        } else if ((!$old_grade_grade->locked and !$old_grade_grade->locktime)
-          and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:lock', $context))) {
-            $mform->hardFreeze('locked');
-            $mform->hardFreeze('locktime');
+            if (($old_grade_grade->locked or $old_grade_grade->locktime)
+              and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:unlock', $context))) {
+                $mform->hardFreeze('locked');
+                $mform->hardFreeze('locktime');
+
+            } else if ((!$old_grade_grade->locked and !$old_grade_grade->locktime)
+              and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:lock', $context))) {
+                $mform->hardFreeze('locked');
+                $mform->hardFreeze('locktime');
+            }
         }
     }
 }
index 6156deedfa36eae5f882f83bd700f5cac20fc013..3919c03b7c1553cd53a373afc28587b3ddc8c615 100644 (file)
@@ -40,6 +40,8 @@ if ($item = get_record('grade_items', 'id', $id, 'courseid', $course->id)) {
         $item->hiddenuntil = 0;
     }
 
+    $item->locked = !empty($item->locked);
+
     // Get Item preferences
     $item->pref_gradedisplaytype = grade_report::get_pref('gradedisplaytype', $id);
     $item->pref_decimalpoints    = grade_report::get_pref('decimalpoints', $id);
@@ -58,6 +60,11 @@ if ($data = $mform->get_data(false)) {
     unset($data->hidden);
     unset($data->hiddenuntil);
 
+    $locked   = empty($data->locked) ? 0: $data->locked;
+    $locktime = empty($data->locktime) ? 0: $data->locktime;
+    unset($data->locked);
+    unset($data->locktime);
+
     $grade_item = new grade_item(array('id'=>$id, 'courseid'=>$courseid));
     grade_item::set_properties($grade_item, $data);
 
@@ -78,6 +85,9 @@ if ($data = $mform->get_data(false)) {
         $grade_item->set_hidden(1);
     }
 
+    $grade_item->set_locktime($locktime); // locktime first - it might be removed when unlocking
+    $grade_item->set_locked($locked, false, true);
+
     // Handle user preferences
     if (isset($data->pref_gradedisplaytype)) {
         if (!grade_report::set_pref('gradedisplaytype', $data->pref_gradedisplaytype, $grade_item->id)) {
index b22fadbf4d88e43fbe703b4d0d7ed42216a26ff7..1fe6457ed7c3fce83d024c16d7a875ac298a7895 100644 (file)
@@ -41,6 +41,8 @@ if ($item = get_record('grade_items', 'id', $id, 'courseid', $course->id)) {
         $item->hiddenuntil = 0;
     }
 
+    $item->locked = !empty($item->locked);
+
     $item->calculation = grade_item::denormalize_formula($item->calculation, $course->id);
 
     if ($item->itemtype == 'mod') {
@@ -63,6 +65,11 @@ if ($data = $mform->get_data(false)) {
     unset($data->hidden);
     unset($data->hiddenuntil);
 
+    $locked   = empty($data->locked) ? 0: $data->locked;
+    $locktime = empty($data->locktime) ? 0: $data->locktime;
+    unset($data->locked);
+    unset($data->locktime);
+
     $grade_item = new grade_item(array('id'=>$id, 'courseid'=>$courseid));
     grade_item::set_properties($grade_item, $data);
 
@@ -130,6 +137,9 @@ if ($data = $mform->get_data(false)) {
         $grade_item->set_hidden(1);
     }
 
+    $grade_item->set_locktime($locktime); // locktime first - it might be removed when unlocking
+    $grade_item->set_locked($locked, false, true);
+
     redirect($returnurl);
 }
 
index b03b9627447c84f8db2333920f273d24bf7d3261..8f9c4e4afaeae8fdd7edc7d6199224d25d362733 100644 (file)
@@ -864,9 +864,9 @@ class grade_tree {
             $icon = 'unlock';
             $tooltip = '';
 
-            if ($element['object']->locktime > 1) { // Change the icon and add a tooltip showing the date
+            if ($element['type'] != 'category' and $element['object']->get_locktime() > 1) { // Change the icon and add a tooltip showing the date
                 $icon = 'locktime';
-                $tooltip = userdate($element['object']->locktime);
+                $tooltip = userdate($element['object']->get_locktime());
             }
 
             if (!has_capability('moodle/grade:manage', $this->context) and !has_capability('moodle/grade:unlock', $this->context)) {
index d7741c229cce9bf5bc33114c57a5d285b6ed0272..ebbe0a557ece719cc4fd29700cf101bb821a6a96 100644 (file)
@@ -221,7 +221,7 @@ $string['linkedactivity'] = 'Linked activity';
 $string['linkedactivityhelp'] = 'An optional activity this outcome item is linked to.';
 $string['lock'] = 'Lock';
 $string['locked'] = 'Locked';
-$string['locktime'] = 'Locked until';
+$string['locktime'] = 'Lock after';
 $string['lowest'] = 'Lowest';
 $string['lowgradeletter'] = 'Low';
 $string['mapfrom'] = 'Map from';
index 921f18854511344ec7e0df1099d003343e454293..2b1ffd9f617557e460dfb3d3ed8ef1afdd3636ae 100644 (file)
@@ -1009,29 +1009,33 @@ class grade_category extends grade_object {
      * Sets the grade_item's locked variable and updates the grade_item.
      * Method named after grade_item::set_locked().
      * @param int $locked 0, 1 or a timestamp int(10) after which date the item will be locked.
+     * @param boolean $cascade lock/unlock child objects too
      * @param boolean $refresh refresh grades when unlocking
      * @return boolean success if category locked (not all children mayb be locked though)
      */
-    function set_locked($lockedstate, $refresh=true) {
+    function set_locked($lockedstate, $cascade=false, $refresh=true) {
         $this->load_grade_item();
 
-        $result = $this->grade_item->set_locked($lockedstate, true);
-        if ($children = grade_item::fetch_all(array('categoryid'=>$this->id))) {
-            foreach($children as $child) {
-                $child->set_locked($lockedstate, false);
-                if (empty($lockedstate) and $refresh) {
-                    //refresh when unlocking
-                    $child->refresh_grades();
+        $result = $this->grade_item->set_locked($lockedstate, $cascade, true);
+
+        if ($cascade) {
+            //process all children - items and categories
+            if ($children = grade_item::fetch_all(array('categoryid'=>$this->id))) {
+                foreach($children as $child) {
+                    $child->set_locked($lockedstate, true, false);
+                    if (empty($lockedstate) and $refresh) {
+                        //refresh when unlocking
+                        $child->refresh_grades();
+                    }
                 }
             }
-        }
-        if ($children = grade_category::fetch_all(array('parent'=>$this->id))) {
-            foreach($children as $child) {
-                $child->set_locked($lockedstate, true);
+            if ($children = grade_category::fetch_all(array('parent'=>$this->id))) {
+                foreach($children as $child) {
+                    $child->set_locked($lockedstate, true, true);
+                }
             }
         }
 
-
         return $result;
     }
 
index 59a90d014b14f9fb6ce88126742a50c46350d6b6..ff2e4ebad90a0bd0075d5214b3d04c28553dfe8d 100644 (file)
@@ -159,9 +159,20 @@ class grade_grade extends grade_object {
      * @return object grade_item.
      */
     function load_grade_item() {
-        if (empty($this->grade_item) and !empty($this->itemid)) {
+        if (empty($this->itemid)) {
+            debugging('Missing itemid');
+            $this->grade_item = null;
+            return null;
+        }
+
+        if (empty($this->grade_item)) {
+            $this->grade_item = grade_item::fetch(array('id'=>$this->itemid));
+
+        } else if ($this->grade_item->id != $this->itemid) {
+            debugging('Itemid mismatch');
             $this->grade_item = grade_item::fetch(array('id'=>$this->itemid));
         }
+
         return $this->grade_item;
     }
 
@@ -254,17 +265,14 @@ class grade_grade extends grade_object {
      * Lock/unlock this grade.
      *
      * @param int $locked 0, 1 or a timestamp int(10) after which date the item will be locked.
+     * @param boolean $cascade ignored param
      * @param boolean $refresh refresh grades when unlocking
      * @return boolean true if sucessful, false if can not set new lock state for grade
      */
-    function set_locked($lockedstate, $refresh=true) {
+    function set_locked($lockedstate, $cascade=false, $refresh=true) {
         $this->load_grade_item();
 
         if ($lockedstate) {
-            if (!empty($this->locked)) {
-                return true; // already locked
-            }
-
             if ($this->grade_item->needsupdate) {
                 //can not lock grade if final not calculated!
                 return false;
@@ -276,17 +284,13 @@ class grade_grade extends grade_object {
             return true;
 
         } else {
-            if (empty($this->locked)) {
-                return true; // not locked
-            }
-
-            if ($this->grade_item->is_locked()) {
-                return false;
+            if (!empty($this->locked) and $this->locktime < time()) {
+                //we have to reset locktime or else it would lock up again
+                $this->locktime = 0;
             }
 
             // remove the locked flag
             $this->locked = 0;
-
             $this->update();
 
             if ($refresh) {
@@ -298,42 +302,79 @@ class grade_grade extends grade_object {
         }
     }
 
-
     /**
-     * Set the locktime for this grade.
-     *
-     * @param int $locktime timestamp for lock to activate
-     * @return boolean true if sucessful, false if can not set new lock state for grade
+     * Lock the grade if needed - make sure this is called only when final grade is valid
      */
-    function set_locktime($locktime) {
+    function check_locktime() {
+        if (!empty($this->locked)) {
+            return; // already locked - do not use is_locked() because we do not want the locking status of grade_item here
+        }
 
-        if ($locktime) {
-            // if current locktime is before, no need to reset
+        if ($this->locktime and $this->locktime < time()) {
+            $this->locked = time();
+            $this->update('locktime');
+        }
+    }
 
-            if ($this->locktime && $this->locktime <= $locktime) {
-                return true;
-            }
 
-            /*
-            if ($this->grade_item->needsupdate) {
-                //can not lock grade if final not calculated!
-                return false;
+    /**
+     * Lock the grade if needed - make sure this is called only when final grades are valid
+     * @param int $courseid
+     * @param array $items array of all grade item ids (speedup only)
+     * @return void
+     */
+    function check_locktime_all($courseid, $items=null) {
+        global $CFG;
+
+        if (!$items) {
+            if (!$items = get_records('grade_items', 'courseid', $courseid, '', 'id')) {
+                return; // no items?
             }
-            */
+            $items = array_keys($items);
+        }
 
-            $this->locktime = $locktime;
-            $this->update();
+        $items_sql = implode(',', $items);
 
-            return true;
+        $now = time(); // no rounding needed, this is not supposed to be called every 10 seconds
 
-        } else {
+        if ($rs = get_recordset_select('grade_grades', "itemid IN ($items_sql) AND locked = 0 AND locktime > 0 AND locktime < $now")) {
+            if ($rs->RecordCount() > 0) {
+                while ($grade = rs_fetch_next_record($rs)) {
+                    $grade_grade = new grade_grade($grade, false);
+                    $grade_grade->locked = time();
+                    $grade_grade->update('locktime');
+                }
+            }
+            rs_close($rs);
+        }
+    }
+
+    /**
+     * Set the locktime for this grade.
+     *
+     * @param int $locktime timestamp for lock to activate
+     * @return void
+     */
+    function set_locktime($locktime) {
+        $this->locktime = $locktime;
+        $this->update();
+    }
 
-            // remove the locktime timestamp
-            $this->locktime = 0;
+    /**
+     * Set the locktime for this grade.
+     *
+     * @return int $locktime timestamp for lock to activate
+     */
+    function get_locktime() {
+        $this->load_grade_item();
 
-            $this->update();
+        $item_locktime = $this->grade_item->get_locktime();
 
-            return true;
+        if (empty($this->locktime) or ($item_locktime and $item_locktime < $this->locktime)) {
+            return $item_locktime;
+
+        } else {
+            return $this->locktime;
         }
     }
 
index 1bd4c0e393c70a0a6505c8060a5d8d6d54c1f598..1c8aaa804b20ca5cdc3709e1b30cc91708396212 100644 (file)
@@ -266,6 +266,7 @@ class grade_item extends grade_object {
         $outcomeiddiff   = $db_item->outcomeid   != $this->outcomeid;
         $multfactordiff  = $db_item->multfactor  != $this->multfactor;
         $plusfactordiff  = $db_item->plusfactor  != $this->plusfactor;
+        $locktimediff    = $db_item->locktime    != $this->locktime;
         $acoefdiff       = $db_item->aggregationcoef != $this->aggregationcoef;
 
         $needsupdatediff = !$db_item->needsupdate &&  $this->needsupdate;    // force regrading only if setting the flag first time
@@ -273,7 +274,7 @@ class grade_item extends grade_object {
 
         return ($calculationdiff || $categorydiff || $gradetypediff || $grademaxdiff || $grademindiff || $scaleiddiff
              || $outcomeiddiff || $multfactordiff || $plusfactordiff || $needsupdatediff
-             || $lockeddiff || $acoefdiff);
+             || $lockeddiff || $acoefdiff || $locktimediff);
     }
 
     /**
@@ -425,61 +426,46 @@ class grade_item extends grade_object {
     /**
      * Locks or unlocks this grade_item and (optionally) all its associated final grades.
      * @param int $locked 0, 1 or a timestamp int(10) after which date the item will be locked.
+     * @param boolean $cascade lock/unlock child objects too
      * @param boolean $refresh refresh grades when unlocking
      * @return boolean true if grade_item all grades updated, false if at least one update fails
      */
-    function set_locked($lockedstate, $refresh=true) {
+    function set_locked($lockedstate, $cascade=false, $refresh=true) {
         if ($lockedstate) {
         /// setting lock
-            if (!empty($this->locked)) {
-                return true; // already locked
-            }
-
             if ($this->needsupdate) {
-                return false; // can not lock grade without first calculating final grade
+                return false; // can not lock grade without first having final grade
             }
 
             $this->locked = time();
             $this->update();
 
-            // this could be improved with direct SQL update
-            $result = true;
-            $grades = $this->get_final();
-            foreach($grades as $g) {
-                $grade = new grade_grade($g, false);
-                $grade->grade_item =& $this;
-                if (!$grade->set_locked(1, false)) {
-                    $result = false;
+            if ($cascade) {
+                $grades = $this->get_final();
+                foreach($grades as $g) {
+                    $grade = new grade_grade($g, false);
+                    $grade->grade_item =& $this;
+                    $grade->set_locked(1, null, false);
                 }
             }
 
-            return $result;
+            return true;
 
         } else {
         /// removing lock
-            if (empty($this->locked)) {
-                return true; // not locked
-            }
-
-            if (!empty($this->locktime) and $this->locktime < time()) {
-                return false; // can not unlock grade item that should be already locked
+            if (!empty($this->locked) and $this->locktime < time()) {
+                //we have to reset locktime or else it would lock up again
+                $this->locktime = 0;
             }
 
             $this->locked = 0;
             $this->update();
 
-            // this could be improved with direct SQL update
-            $result = true;
-            if ($grades = grade_grade::fetch_all(array('itemid'=>$this->id))) {
-                foreach($grades as $grade) {
-                    $grade->grade_item =& $this;
-
-                    if (!empty($grade->locktime) and $grade->locktime < time()) {
-                        $result = false; // can not unlock grade that should be already locked
-                    }
-
-                    if (!$grade->set_locked(0, false)) {
-                        $result = false;
+            if ($cascade) {
+                if ($grades = grade_grade::fetch_all(array('itemid'=>$this->id))) {
+                    foreach($grades as $grade) {
+                        $grade->grade_item =& $this;
+                        $grade->set_locked(0, null, false);
                     }
                 }
             }
@@ -489,47 +475,64 @@ class grade_item extends grade_object {
                 $this->refresh_grades();
             }
 
-            return $result;
-
+            return true;
         }
     }
 
     /**
-     * Set the locktime for this grade.
-     *
-     * @param int $locktime timestamp for lock to activate
-     * @return boolean true if sucessful, false if can not set new lock state for grade
+     * Lock the grade if needed - make sure this is called only when final grades are valid
      */
-    function set_locktime($locktime) {
-
-        if ($locktime) {
-            // if current locktime is before, no need to reset
-
-            if ($this->locktime && $this->locktime <= $locktime) {
-                return true;
-            }
-
-            /*
-            if ($this->grade_item->needsupdate) {
-                //can not lock grade if final not calculated!
-                return false;
-            }
-            */
+    function check_locktime() {
+        if (!empty($this->locked)) {
+            return; // already locked
+        }
 
-            $this->locktime = $locktime;
-            $this->update();
+        if ($this->locktime and $this->locktime < time()) {
+            $this->locked = time();
+            $this->update('locktime');
+        }
+    }
 
-            return true;
+    /**
+     * Lock all grade items if needed - make sure this is called only when final grades are valid
+     * @static
+     * @param int $courseid
+     * @return void
+     */
+    function check_locktime_all($courseid) {
+        global $CFG;
 
-        } else {
+        $now = time(); // no need to round it here, executed from cron only
+        $sql = "SELECT * FROM {$CFG->prefix}grade_items
+                 WHERE courseid=$courseid AND locked = 0 AND locktime > 0 AND locktime < $now";
 
-            // remove the locktime timestamp
-            $this->locktime = 0;
+        if ($items = get_records_sql($sql)) {
+            foreach ($items as $item) {
+                $grade_item = new grade_grade($item, false);
+                $grade_item->locked = time();
+                $grade_item->update('locktime');
+            }
+        }
+    }
 
-            $this->update();
+    /**
+     * Set the locktime for this grade item.
+     *
+     * @param int $locktime timestamp for lock to activate
+     * @return void
+     */
+    function set_locktime($locktime) {
+        $this->locktime = $locktime;
+        $this->update();
+    }
 
-            return true;
-        }
+    /**
+     * Set the locktime for this grade item.
+     *
+     * @return int $locktime timestamp for lock to activate
+     */
+    function get_locktime() {
+        return $this->locktime;
     }
 
     /**
@@ -579,11 +582,6 @@ class grade_item extends grade_object {
         $this->needsupdate = 0;
         //do not use $this->update() because we do not want this logged in grade_item_history
         set_field('grade_items', 'needsupdate', 0, 'id', $this->id);
-
-        if (!empty($this->locktime) and empty($this->locked) and $this->locktime < time()) {
-            // time to lock this grade_item
-            $this->set_locked(true);
-        }
     }
 
     /**
@@ -640,12 +638,13 @@ class grade_item extends grade_object {
         if ($rs) {
             if ($rs->RecordCount() > 0) {
                 while ($grade_record = rs_fetch_next_record($rs)) {
+                    $grade = new grade_grade($grade_record, false);
+
                     if (!empty($grade_record->locked) or !empty($grade_record->overridden)) {
                         // this grade is locked - final grade must be ok
                         continue;
                     }
 
-                    $grade = new grade_grade($grade_record, false);
                     $grade->finalgrade = $this->adjust_grade($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax);
 
                     if ($grade_record->finalgrade !== $grade->finalgrade) {
@@ -653,13 +652,6 @@ class grade_item extends grade_object {
                             $result = "Internal error updating final grade";
                         }
                     }
-
-                    // time to lock this grade?
-                    if (!empty($grade->locktime) and empty($grade->locked) and $grade->locktime < time()) {
-                        $grade->locked = time();
-                        $grade->grade_item =& $this;
-                        $grade->set_locked(true);
-                    }
                 }
             }
             rs_close($rs);
@@ -1238,27 +1230,28 @@ class grade_item extends grade_object {
         if (!$grade = grade_grade::fetch(array('itemid'=>$this->id, 'userid'=>$userid))) {
             $grade = new grade_grade(array('itemid'=>$this->id, 'userid'=>$userid), false);
         }
-
         $grade->grade_item =& $this; // prevent db fetching of this grade_item
-        $oldgrade = new object();
-        $oldgrade->finalgrade  = $grade->finalgrade;
-        $oldgrade->rawgrade    = $grade->rawgrade;
-        $oldgrade->rawgrademin = $grade->rawgrademin;
-        $oldgrade->rawgrademax = $grade->rawgrademax;
-        $oldgrade->rawscaleid  = $grade->rawscaleid;
-        $oldgrade->overridden  = $grade->overridden;
 
         if ($grade->is_locked()) {
             // do not update locked grades at all
             return false;
         }
 
-        if (!empty($grade->locktime) and $grade->locktime < time()) {
-            // do not update grades that should be already locked
-            // this does not solve all problems, cron is still needed to recalculate the final grades periodically
+        $locktime = $grade->get_locktime();
+        if ($locktime and $locktime < time()) {
+            // do not update grades that should be already locked and force regrade
+            $this->force_regrading();
             return false;
         }
 
+        $oldgrade = new object();
+        $oldgrade->finalgrade  = $grade->finalgrade;
+        $oldgrade->rawgrade    = $grade->rawgrade;
+        $oldgrade->rawgrademin = $grade->rawgrademin;
+        $oldgrade->rawgrademax = $grade->rawgrademax;
+        $oldgrade->rawscaleid  = $grade->rawscaleid;
+        $oldgrade->overridden  = $grade->overridden;
+
         if ($finalgrade !== false) {
             if (!is_null($finalgrade)) {
                 $grade->finalgrade = bounded_number($this->grademin, $finalgrade, $this->grademax);
@@ -1266,7 +1259,10 @@ class grade_item extends grade_object {
                 $grade->finalgrade = $finalgrade;
             }
 
-            if ($this->is_outcome_item()) {
+            if ($this->is_manual_item() and !$this->is_calculated()) {
+                // no overriding on manual grades - raw not used
+
+            } else if ($this->is_outcome_item() and !$this->is_calculated()) {
                 // no updates of raw grades for outcomes - raw grades not used
 
             } else if (!$this->is_normal_item() or $this->plusfactor != 0 or $this->multfactor != 1
@@ -1360,26 +1356,27 @@ class grade_item extends grade_object {
         if (!$grade = grade_grade::fetch(array('itemid'=>$this->id, 'userid'=>$userid))) {
             $grade = new grade_grade(array('itemid'=>$this->id, 'userid'=>$userid), false);
         }
-
         $grade->grade_item =& $this; // prevent db fetching of this grade_item
-        $oldgrade = new object();
-        $oldgrade->finalgrade  = $grade->finalgrade;
-        $oldgrade->rawgrade    = $grade->rawgrade;
-        $oldgrade->rawgrademin = $grade->rawgrademin;
-        $oldgrade->rawgrademax = $grade->rawgrademax;
-        $oldgrade->rawscaleid  = $grade->rawscaleid;
 
         if ($grade->is_locked()) {
             // do not update locked grades at all
             return false;
         }
 
-        if (!empty($grade->locktime) and $grade->locktime < time()) {
-            // do not update grades that should be already locked
-            // this does not solve all problems, cron is still needed to recalculate the final grades periodically
+        $locktime = $grade->get_locktime();
+        if ($locktime and $locktime < time()) {
+            // do not update grades that should be already locked and force regrade
+            $this->force_regrading();
             return false;
         }
 
+        $oldgrade = new object();
+        $oldgrade->finalgrade  = $grade->finalgrade;
+        $oldgrade->rawgrade    = $grade->rawgrade;
+        $oldgrade->rawgrademin = $grade->rawgrademin;
+        $oldgrade->rawgrademax = $grade->rawgrademax;
+        $oldgrade->rawscaleid  = $grade->rawscaleid;
+
         // fist copy current grademin/max and scale
         $grade->rawgrademin = $this->grademin;
         $grade->rawgrademax = $this->grademax;
@@ -1600,6 +1597,10 @@ class grade_item extends grade_object {
             $grade->update('system');
         }
 
+        if ($result !== false) {
+            //lock grade if needed
+        }
+
         if ($result === false) {
             return false;
         } else {
index 8069ff26531b278c12d76ecf707d628e9da4e8e2..ad73350f6857b6955de80fa1d8560254c43b962f 100644 (file)
@@ -435,8 +435,7 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null)
     $depends_on = array();
 
     // first mark all category and calculated items as needing regrading
-    // this is slower, but 100% accurate - this function is called only when there is
-    // a change in grading setup, update of individual grade does not trigger this function
+    // this is slower, but 100% accurate
     foreach ($grade_items as $gid=>$gitem) {
         if (!empty($updated_item) and $updated_item->id == $gid) {
             $grade_items[$gid]->needsupdate = 1;
@@ -480,8 +479,10 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null)
 
                 if ($result === true) {
                     $grade_items[$gid]->regrading_finished();
+                    $grade_items[$gid]->check_locktime(); // do the locktime item locking
                     $count++;
                     $finalids[] = $gid;
+
                 } else {
                     $grade_items[$gid]->force_regrading();
                     $errors[$gid] = $result;
@@ -508,6 +509,10 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null)
     }
 
     if (count($errors) == 0) {
+        if (empty($userid)) {
+            // do the locktime locking of grades, but only when doing full regrading
+            grade_grade::check_locktime_all($courseid, $gids);
+        }
         return true;
     } else {
         return $errors;