public function execute() { global $DB; $TIMELIMITHOURS = 8; $timebound = time() - $TIMELIMITHOURS * 60 * 60; $sql = 'SELECT id, itemid, userid FROM {grade_grades} WHERE locked = 0 AND overridden > 0 AND overridden < ?'; $records = $DB->get_records_sql($sql, array($timebound)); foreach ($records as $record) { $gradeitem = \grade_item::fetch(array('id' => $record->itemid)); $grades = \grade_grade::fetch_users_grades($gradeitem, array($record->userid)); $grades[$record->userid]->set_locked(1); } }
/** * Tests grade_report_grader::process_data() * * process_data() processes submitted grade and feedback data */ public function test_process_data() { global $DB, $CFG; $this->resetAfterTest(true); $course = $this->getDataGenerator()->create_course(); $coursecontext = context_course::instance($course->id); // Create and enrol a student. $student = $this->getDataGenerator()->create_user(array('username' => 'Student Sam')); $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); $this->getDataGenerator()->enrol_user($student->id, $course->id, $role->id); // Test with limited grades. $CFG->unlimitedgrades = 0; $forummax = 80; $forum1 = $this->getDataGenerator()->create_module('forum', array('assessed' => 1, 'scale' => $forummax, 'course' => $course->id)); // Switch the stdClass instance for a grade item instance. $forum1 = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'forum', 'iteminstance' => $forum1->id, 'courseid' => $course->id)); $report = $this->create_report($course, $coursecontext); $testgrade = 60.0; $data = new stdClass(); $data->id = $course->id; $data->report = 'grader'; $data->grade = array(); $data->grade[$student->id] = array(); $data->grade[$student->id][$forum1->id] = $testgrade; $warnings = $report->process_data($data); $this->assertEquals(count($warnings), 0); $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id)); $this->assertEquals($studentgrade->finalgrade, $testgrade); // Grade above max. Should be pulled down to max. $toobig = 200.0; $data->grade[$student->id][$forum1->id] = $toobig; $warnings = $report->process_data($data); $this->assertEquals(count($warnings), 1); $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id)); $this->assertEquals($studentgrade->finalgrade, $forummax); // Grade below min. Should be pulled up to min. $toosmall = -10.0; $data->grade[$student->id][$forum1->id] = $toosmall; $warnings = $report->process_data($data); $this->assertEquals(count($warnings), 1); $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id)); $this->assertEquals($studentgrade->finalgrade, 0); // Test unlimited grades so we can give a student a grade about max. $CFG->unlimitedgrades = 1; $data->grade[$student->id][$forum1->id] = $toobig; $warnings = $report->process_data($data); $this->assertEquals(count($warnings), 0); $studentgrade = grade_grade::fetch(array('itemid' => $forum1->id, '' => $student->id)); $this->assertEquals($studentgrade->finalgrade, $toobig); }
/** * Tests the gradebookservice get grade service. * * @return void */ public function test_get_grade() { global $DB; $callback = 'block_mhaairs_gradebookservice_external::get_grade'; $this->set_user('admin'); // Add mhaairs grade item directly. $params = array('courseid' => $this->course->id, 'itemtype' => 'manual', 'itemmodule' => 'mhaairs', 'iteminstance' => 101, 'itemname' => 'MH Assignment'); $gitem = new \grade_item($params, false); $gitem->insert('mhaairs'); // Add user grade directly. $params = array('itemid' => $gitem->id, 'userid' => $this->student1->id, 'finalgrade' => '95'); $ggrade = new \grade_grade($params, false); $ggrade->insert('mhaairs'); // Service params. $serviceparams = array('source' => 'mhaairs', 'courseid' => $this->course->id, 'itemtype' => 'manual', 'itemmodule' => 'mhaairs', 'iteminstance' => 101, 'itemnumber' => 0, 'grades' => null, 'itemdetails' => null); // Grade details. $grades = array('userid' => 'student1', 'identity_type' => ''); $gradesjson = urlencode(json_encode($grades)); $serviceparams['grades'] = $gradesjson; $result = call_user_func_array($callback, $serviceparams); $this->assertEquals('MH Assignment', $result['item']['itemname']); $this->assertEquals($this->student1->id, $result['grades'][0]['userid']); $this->assertEquals(95, $result['grades'][0]['grade']); }
public function test_task_timefilter() { $task = new \local_gradelock\task\lock_grades(); $grade_grade = new grade_grade(); $grade_grade->itemid = $this->grade_items[0]->id; $grade_grade->userid = 10; $grade_grade->rawgrade = 88; $grade_grade->rawgrademax = 110; $grade_grade->rawgrademin = 18; $grade_grade->load_grade_item(); $grade_grade->insert(); $grade_grade->grade_item->update_final_grade($this->user[0]->id, 100, 'gradebook', '', FORMAT_MOODLE); $grade_grade->update(); $task->execute(); $grade_grade = grade_grade::fetch(array('userid' => $this->user[0]->id, 'itemid' => $this->grade_items[0]->id)); $this->assertFalse($grade_grade->is_locked()); }
public function cleanup() { // cleanup any clickers before the test $user_id = iclicker_service::require_user(); $results = iclicker_service::get_registrations_by_user($user_id); if ($results) { echo "cleanup registrations for user: {$user_id} " . PHP_EOL; foreach ($results as $reg) { if ($reg->clicker_id == $this->clicker_id) { iclicker_service::remove_registration($reg->id); echo "cleanup: {$reg->id} " . PHP_EOL; } } } // cleanup the test grades $def_grade_cats = grade_category::fetch_all(array('courseid' => $this->courseid, 'fullname' => iclicker_service::GRADE_CATEGORY_NAME)); $stuff_grade_cats = grade_category::fetch_all(array('courseid' => $this->courseid, 'fullname' => 'stuff')); $grade_cats = $def_grade_cats; if (is_array($def_grade_cats) && is_array($stuff_grade_cats)) { $grade_cats = array_merge($def_grade_cats, $stuff_grade_cats); } else { if (is_array($stuff_grade_cats)) { $grade_cats = $stuff_grade_cats; } } if ($grade_cats) { foreach ($grade_cats as $cat) { $grade_items = grade_item::fetch_all(array('courseid' => $this->courseid, 'categoryid' => $cat->id)); if ($grade_items) { foreach ($grade_items as $item) { $grades = grade_grade::fetch_all(array('itemid' => $item->id)); if ($grades) { foreach ($grades as $grade) { $grade->delete("cleanup"); } } $item->delete("cleanup"); } } $cat->delete("cleanup"); } } }
/** * Parses the array in search of a given eid and returns a element object with * information about the element it has found. * @param int $eid Gradetree Element ID * @return object element */ public function locate_element($eid) { // it is a grade - construct a new object if (strpos($eid, 'n') === 0) { if (!preg_match('/n(\\d+)u(\\d+)/', $eid, $matches)) { return null; } $itemid = $matches[1]; $userid = $matches[2]; //extra security check - the grade item must be in this tree if (!($item_el = $this->locate_element('i' . $itemid))) { return null; } // $gradea->id may be null - means does not exist yet $grade = new grade_grade(array('itemid' => $itemid, 'userid' => $userid)); $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods! return array('eid' => 'n' . $itemid . 'u' . $userid, 'object' => $grade, 'type' => 'grade'); } else { if (strpos($eid, 'g') === 0) { $id = (int) substr($eid, 1); if (!($grade = grade_grade::fetch(array('id' => $id)))) { return null; } //extra security check - the grade item must be in this tree if (!($item_el = $this->locate_element('i' . $grade->itemid))) { return null; } $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods! return array('eid' => 'g' . $id, 'object' => $grade, 'type' => 'grade'); } } // it is a category or item foreach ($this->levels as $row) { foreach ($row as $element) { if ($element['type'] == 'filler') { continue; } if ($element['eid'] == $eid) { return $element; } } } return null; }
/** * This function is called after the table has been built and the aggregationhints * have been collected. We need this info to walk up the list of parents of each * grade_item. * * @param $element - An array containing the table data for the current row. */ public function fill_contributions_column($element) { // Recursively iterate through all child elements. if (isset($element['children'])) { foreach ($element['children'] as $key => $child) { $this->fill_contributions_column($element['children'][$key]); } } else { if ($element['type'] == 'item') { // This is a grade item (We don't do this for categories or we would double count). $grade_object = $element['object']; $itemid = $grade_object->id; // Ignore anything with no hint - e.g. a hidden row. if (isset($this->aggregationhints[$itemid])) { // Normalise the gradeval. $gradecat = $grade_object->load_parent_category(); if ($gradecat->aggregation == GRADE_AGGREGATE_SUM) { // Natural aggregation/Sum of grades does not consider the mingrade, cannot traditionnally normalise it. $graderange = $this->aggregationhints[$itemid]['grademax']; if ($graderange != 0) { $gradeval = $this->aggregationhints[$itemid]['grade'] / $graderange; } else { $gradeval = 0; } } else { $gradeval = grade_grade::standardise_score($this->aggregationhints[$itemid]['grade'], $this->aggregationhints[$itemid]['grademin'], $this->aggregationhints[$itemid]['grademax'], 0, 1); } // Multiply the normalised value by the weight // of all the categories higher in the tree. $parent = null; do { if (!is_null($this->aggregationhints[$itemid]['weight'])) { $gradeval *= $this->aggregationhints[$itemid]['weight']; } else { if (empty($parent)) { // If we are in the first loop, and the weight is null, then we cannot calculate the contribution. $gradeval = null; break; } } // The second part of this if is to prevent infinite loops // in case of crazy data. if (isset($this->aggregationhints[$itemid]['parent']) && $this->aggregationhints[$itemid]['parent'] != $itemid) { $parent = $this->aggregationhints[$itemid]['parent']; $itemid = $parent; } else { // We are at the top of the tree. $parent = false; } } while ($parent); // Finally multiply by the course grademax. if (!is_null($gradeval)) { // Convert to percent. $gradeval *= 100; } // Now we need to loop through the "built" table data and update the // contributions column for the current row. $header_row = "row_{$grade_object->id}_{$this->user->id}"; foreach ($this->tabledata as $key => $row) { if (isset($row['itemname']) && $row['itemname']['id'] == $header_row) { // Found it - update the column. $content = '-'; if (!is_null($gradeval)) { $decimals = $grade_object->get_decimals(); $content = format_float($gradeval, $decimals, true) . ' %'; } $this->tabledata[$key]['contributiontocoursetotal']['content'] = $content; break; } } } } } }
/** * Internal function for category grades summing * * @param grade_grade $grade The grade item * @param float $oldfinalgrade Old Final grade * @param array $items Grade items * @param array $grade_values Grade values * @param array $excluded Excluded */ private function sum_grades(&$grade, $oldfinalgrade, $items, $grade_values, $excluded) { if (empty($items)) { return null; } // ungraded and excluded items are not used in aggregation foreach ($grade_values as $itemid => $v) { if (is_null($v)) { unset($grade_values[$itemid]); } else { if (in_array($itemid, $excluded)) { unset($grade_values[$itemid]); } } } // use 0 if grade missing, droplow used and aggregating all items if (!$this->aggregateonlygraded and !empty($this->droplow)) { foreach ($items as $itemid => $value) { if (!isset($grade_values[$itemid]) and !in_array($itemid, $excluded)) { $grade_values[$itemid] = 0; } } } $this->apply_limit_rules($grade_values, $items); $sum = array_sum($grade_values); $grade->finalgrade = $this->grade_item->bounded_grade($sum); // update in db if changed if (grade_floats_different($grade->finalgrade, $oldfinalgrade)) { $grade->update('aggregation'); } return; }
protected function process_grade_grade($data) { $data = (object)($data); unset($data->id); $data->itemid = $this->get_new_parentid('grade_item'); $data->userid = $this->get_mappingid('user', $data->userid); $data->usermodified = $this->get_mappingid('user', $data->usermodified); $data->rawscaleid = $this->get_mappingid('scale', $data->rawscaleid); // TODO: Ask, all the rest of locktime/exported... work with time... to be rolled? $data->overridden = $this->apply_date_offset($data->overridden); $grade = new grade_grade($data, false); $grade->insert('restore'); // no need to save any grade_grade mapping }
/** * If the requirements are met - reopen the submission for another attempt. * Only call this function when grading the latest attempt. * * @param int $userid The userid. * @param stdClass $submission The submission (may be a group submission). * @param bool $addattempt - True if the "allow another attempt" checkbox was checked. * @return bool - true if another attempt was added. */ protected function reopen_submission_if_required($userid, $submission, $addattempt) { $instance = $this->get_instance(); $maxattemptsreached = !empty($submission) && $submission->attemptnumber >= $instance->maxattempts - 1 && $instance->maxattempts != ASSIGN_UNLIMITED_ATTEMPTS; $shouldreopen = false; if ($instance->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS) { // Check the gradetopass from the gradebook. $gradeitem = $this->get_grade_item(); if ($gradeitem) { $gradegrade = grade_grade::fetch(array('userid' => $userid, 'itemid' => $gradeitem->id)); // Do not reopen if is_passed returns null, e.g. if there is no pass criterion set. if ($gradegrade && $gradegrade->is_passed() === false) { $shouldreopen = true; } } } if ($instance->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL && !empty($addattempt)) { $shouldreopen = true; } if ($shouldreopen && !$maxattemptsreached) { $this->add_attempt($userid); return true; } return false; }
/** * Tests grade_report::blank_hidden_total_and_adjust_bounds() */ public function test_blank_hidden_total_and_adjust_bounds() { global $DB; $this->resetAfterTest(true); $student = $this->getDataGenerator()->create_user(); $this->setUser($student); // Create a course and two activities. // One activity will be hidden. $course = $this->getDataGenerator()->create_course(); $coursegradeitem = grade_item::fetch_course_item($course->id); $coursecontext = context_course::instance($course->id); $data = $this->getDataGenerator()->create_module('data', array('assessed' => 1, 'scale' => 100, 'course' => $course->id)); $datacm = get_coursemodule_from_id('data', $data->cmid); $forum = $this->getDataGenerator()->create_module('forum', array('assessed' => 1, 'scale' => 100, 'course' => $course->id)); $forumcm = get_coursemodule_from_id('forum', $forum->cmid); // Insert student grades for the two activities. $gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'data', 'iteminstance' => $data->id, 'courseid' => $course->id)); $datagrade = 50; $grade_grade = new grade_grade(); $grade_grade->itemid = $gi->id; $grade_grade->userid = $student->id; $grade_grade->rawgrade = $datagrade; $grade_grade->finalgrade = $datagrade; $grade_grade->rawgrademax = 100; $grade_grade->rawgrademin = 0; $grade_grade->timecreated = time(); $grade_grade->timemodified = time(); $grade_grade->insert(); $gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'forum', 'iteminstance' => $forum->id, 'courseid' => $course->id)); $forumgrade = 70; $grade_grade = new grade_grade(); $grade_grade->itemid = $gi->id; $grade_grade->userid = $student->id; $grade_grade->rawgrade = $forumgrade; $grade_grade->finalgrade = $forumgrade; $grade_grade->rawgrademax = 100; $grade_grade->rawgrademin = 0; $grade_grade->timecreated = time(); $grade_grade->timemodified = time(); $grade_grade->insert(); // Hide the database activity. set_coursemodule_visible($datacm->id, 0); $gpr = new grade_plugin_return(array('type' => 'report', 'courseid' => $course->id)); $report = new grade_report_test($course->id, $gpr, $coursecontext, $student); // Should return the supplied student total grade regardless of hiding. $report->showtotalsifcontainhidden = array($course->id => GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN); $result = $report->blank_hidden_total_and_adjust_bounds($course->id, $coursegradeitem, $datagrade + $forumgrade); $this->assertEquals(array('grade' => $datagrade + $forumgrade, 'grademax' => $coursegradeitem->grademax, 'grademin' => $coursegradeitem->grademin, 'aggregationstatus' => 'unknown', 'aggregationweight' => null), $result); // Should blank the student total as course grade depends on a hidden item. $report->showtotalsifcontainhidden = array($course->id => GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN); $result = $report->blank_hidden_total_and_adjust_bounds($course->id, $coursegradeitem, $datagrade + $forumgrade); $this->assertEquals(array('grade' => null, 'grademax' => $coursegradeitem->grademax, 'grademin' => $coursegradeitem->grademin, 'aggregationstatus' => 'unknown', 'aggregationweight' => null), $result); // Should return the course total minus the hidden database activity grade. $report->showtotalsifcontainhidden = array($course->id => GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN); $result = $report->blank_hidden_total_and_adjust_bounds($course->id, $coursegradeitem, $datagrade + $forumgrade); $this->assertEquals(array('grade' => floatval($forumgrade), 'grademax' => $coursegradeitem->grademax, 'grademin' => $coursegradeitem->grademin, 'aggregationstatus' => 'unknown', 'aggregationweight' => null), $result); // Note: we cannot simply hide modules and call $report->blank_hidden_total() again. // It stores grades in a static variable so $report->blank_hidden_total() will return incorrect totals // In practice this isn't a problem. Grade visibility isn't altered mid-request outside of the unit tests. // Add a second course to test: // 1) How a course with no visible activities behaves. // 2) That $report->blank_hidden_total() correctly moves on to the new course. $course = $this->getDataGenerator()->create_course(); $coursegradeitem = grade_item::fetch_course_item($course->id); $coursecontext = context_course::instance($course->id); $data = $this->getDataGenerator()->create_module('data', array('assessed' => 1, 'scale' => 100, 'course' => $course->id)); $datacm = get_coursemodule_from_id('data', $data->cmid); $forum = $this->getDataGenerator()->create_module('forum', array('assessed' => 1, 'scale' => 100, 'course' => $course->id)); $forumcm = get_coursemodule_from_id('forum', $forum->cmid); $gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'data', 'iteminstance' => $data->id, 'courseid' => $course->id)); $datagrade = 50; $grade_grade = new grade_grade(); $grade_grade->itemid = $gi->id; $grade_grade->userid = $student->id; $grade_grade->rawgrade = $datagrade; $grade_grade->finalgrade = $datagrade; $grade_grade->rawgrademax = 100; $grade_grade->rawgrademin = 0; $grade_grade->timecreated = time(); $grade_grade->timemodified = time(); $grade_grade->insert(); $gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'forum', 'iteminstance' => $forum->id, 'courseid' => $course->id)); $forumgrade = 70; $grade_grade = new grade_grade(); $grade_grade->itemid = $gi->id; $grade_grade->userid = $student->id; $grade_grade->rawgrade = $forumgrade; $grade_grade->finalgrade = $forumgrade; $grade_grade->rawgrademax = 100; $grade_grade->rawgrademin = 0; $grade_grade->timecreated = time(); $grade_grade->timemodified = time(); $grade_grade->insert(); // Hide both activities. set_coursemodule_visible($datacm->id, 0); set_coursemodule_visible($forumcm->id, 0); $gpr = new grade_plugin_return(array('type' => 'report', 'courseid' => $course->id)); $report = new grade_report_test($course->id, $gpr, $coursecontext, $student); // Should return the supplied student total grade regardless of hiding. $report->showtotalsifcontainhidden = array($course->id => GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN); $result = $report->blank_hidden_total_and_adjust_bounds($course->id, $coursegradeitem, $datagrade + $forumgrade); $this->assertEquals(array('grade' => $datagrade + $forumgrade, 'grademax' => $coursegradeitem->grademax, 'grademin' => $coursegradeitem->grademin, 'aggregationstatus' => 'unknown', 'aggregationweight' => null), $result); // Should blank the student total as course grade depends on a hidden item. $report->showtotalsifcontainhidden = array($course->id => GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN); $result = $report->blank_hidden_total_and_adjust_bounds($course->id, $coursegradeitem, $datagrade + $forumgrade); $this->assertEquals(array('grade' => null, 'grademax' => $coursegradeitem->grademax, 'grademin' => $coursegradeitem->grademin, 'aggregationstatus' => 'unknown', 'aggregationweight' => null), $result); // Should return the course total minus the hidden activity grades. // They are both hidden so should return null. $report->showtotalsifcontainhidden = array($course->id => GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN); $result = $report->blank_hidden_total_and_adjust_bounds($course->id, $coursegradeitem, $datagrade + $forumgrade); $this->assertEquals(array('grade' => null, 'grademax' => $coursegradeitem->grademax, 'grademin' => $coursegradeitem->grademin, 'aggregationstatus' => 'unknown', 'aggregationweight' => null), $result); }
/** * Return array of grade item ids that are either hidden or indirectly depend * on hidden grades, excluded grades are not returned. * THIS IS A REALLY BIG HACK! to be replaced by conditional aggregation of hidden grades in 2.0 * * @param array $grade_grades all course grades of one user, & used for better internal caching * @param array $grade_items array of grade items, & used for better internal caching * @return array This is an array of 3 arrays: * unknown => list of item ids that may be affected by hiding (with the calculated grade as the value) * altered => list of item ids that are definitely affected by hiding (with the calculated grade as the value) * alteredgrademax => for each item in altered or unknown, the new value of the grademax * alteredgrademin => for each item in altered or unknown, the new value of the grademin * alteredgradestatus => for each item with a modified status - the value of the new status * alteredgradeweight => for each item with a modified weight - the value of the new weight */ public static function get_hiding_affected(&$grade_grades, &$grade_items) { global $CFG; if (count($grade_grades) !== count($grade_items)) { print_error('invalidarraysize', 'debug', '', 'grade_grade::get_hiding_affected()!'); } $dependson = array(); $todo = array(); $unknown = array(); // can not find altered $altered = array(); // altered grades $alteredgrademax = array(); // Altered grade max values. $alteredgrademin = array(); // Altered grade min values. $alteredaggregationstatus = array(); // Altered aggregation status. $alteredaggregationweight = array(); // Altered aggregation weight. $dependencydepth = array(); $hiddenfound = false; foreach ($grade_grades as $itemid => $unused) { $grade_grade =& $grade_grades[$itemid]; // We need the immediate dependencies of all every grade_item so we can calculate nested dependencies. $dependson[$grade_grade->itemid] = $grade_items[$grade_grade->itemid]->depends_on(); if ($grade_grade->is_excluded()) { //nothing to do, aggregation is ok } else { if ($grade_grade->is_hidden()) { $hiddenfound = true; $altered[$grade_grade->itemid] = null; $alteredaggregationstatus[$grade_grade->itemid] = 'dropped'; $alteredaggregationweight[$grade_grade->itemid] = 0; } else { if ($grade_grade->is_locked() or $grade_grade->is_overridden()) { // no need to recalculate locked or overridden grades } else { if (!empty($dependson[$grade_grade->itemid])) { $dependencydepth[$grade_grade->itemid] = 1; $todo[] = $grade_grade->itemid; } } } } } // Flatten the dependency tree and count number of branches to each leaf. self::flatten_dependencies_array($dependson, $dependencydepth); if (!$hiddenfound) { return array('unknown' => array(), 'altered' => array(), 'alteredgrademax' => array(), 'alteredgrademin' => array(), 'alteredaggregationstatus' => array(), 'alteredaggregationweight' => array()); } // This line ensures that $dependencydepth has the same number of items as $todo. $dependencydepth = array_intersect_key($dependencydepth, array_flip($todo)); // We need to resort the todo list by the dependency depth. This guarantees we process the leaves, then the branches. array_multisort($dependencydepth, $todo); $max = count($todo); $hidden_precursors = null; for ($i = 0; $i < $max; $i++) { $found = false; foreach ($todo as $key => $do) { $hidden_precursors = array_intersect($dependson[$do], $unknown); if ($hidden_precursors) { // this item depends on hidden grade indirectly $unknown[$do] = $do; unset($todo[$key]); $found = true; continue; } else { if (!array_intersect($dependson[$do], $todo)) { $hidden_precursors = array_intersect($dependson[$do], array_keys($altered)); if (!$hidden_precursors) { // hiding does not affect this grade unset($todo[$key]); $found = true; continue; } else { // depends on altered grades - we should try to recalculate if possible if ($grade_items[$do]->is_calculated() or !$grade_items[$do]->is_category_item() and !$grade_items[$do]->is_course_item()) { // This is a grade item that is not a category or course and has been affected by grade hiding. // I guess this means it is a calculation that needs to be recalculated. $unknown[$do] = $do; unset($todo[$key]); $found = true; continue; } else { // This is a grade category (or course). $grade_category = $grade_items[$do]->load_item_category(); // Build a new list of the grades in this category. $values = array(); $immediatedepends = $grade_items[$do]->depends_on(); foreach ($immediatedepends as $itemid) { if (array_key_exists($itemid, $altered)) { //nulling an altered precursor $values[$itemid] = $altered[$itemid]; if (is_null($values[$itemid])) { // This means this was a hidden grade item removed from the result. unset($values[$itemid]); } } elseif (empty($values[$itemid])) { $values[$itemid] = $grade_grades[$itemid]->finalgrade; } } foreach ($values as $itemid => $value) { if ($grade_grades[$itemid]->is_excluded()) { unset($values[$itemid]); $alteredaggregationstatus[$itemid] = 'excluded'; $alteredaggregationweight[$itemid] = null; continue; } // The grade min/max may have been altered by hiding. $grademin = $grade_items[$itemid]->grademin; if (isset($alteredgrademin[$itemid])) { $grademin = $alteredgrademin[$itemid]; } $grademax = $grade_items[$itemid]->grademax; if (isset($alteredgrademax[$itemid])) { $grademax = $alteredgrademax[$itemid]; } $values[$itemid] = grade_grade::standardise_score($value, $grademin, $grademax, 0, 1); } if ($grade_category->aggregateonlygraded) { foreach ($values as $itemid => $value) { if (is_null($value)) { unset($values[$itemid]); $alteredaggregationstatus[$itemid] = 'novalue'; $alteredaggregationweight[$itemid] = null; } } } else { foreach ($values as $itemid => $value) { if (is_null($value)) { $values[$itemid] = 0; } } } // limit and sort $allvalues = $values; $grade_category->apply_limit_rules($values, $grade_items); $moredropped = array_diff($allvalues, $values); foreach ($moredropped as $drop => $unused) { $alteredaggregationstatus[$drop] = 'dropped'; $alteredaggregationweight[$drop] = null; } foreach ($values as $itemid => $val) { if ($grade_category->is_extracredit_used() && $grade_items[$itemid]->aggregationcoef > 0) { $alteredaggregationstatus[$itemid] = 'extra'; } } asort($values, SORT_NUMERIC); // let's see we have still enough grades to do any statistics if (count($values) == 0) { // not enough attempts yet $altered[$do] = null; unset($todo[$key]); $found = true; continue; } $usedweights = array(); $adjustedgrade = $grade_category->aggregate_values_and_adjust_bounds($values, $grade_items, $usedweights); // recalculate the rawgrade back to requested range $finalgrade = grade_grade::standardise_score($adjustedgrade['grade'], 0, 1, $adjustedgrade['grademin'], $adjustedgrade['grademax']); foreach ($usedweights as $itemid => $weight) { if (!isset($alteredaggregationstatus[$itemid])) { $alteredaggregationstatus[$itemid] = 'used'; } $alteredaggregationweight[$itemid] = $weight; } $finalgrade = $grade_items[$do]->bounded_grade($finalgrade); $alteredgrademin[$do] = $adjustedgrade['grademin']; $alteredgrademax[$do] = $adjustedgrade['grademax']; // We need to muck with the "in-memory" grade_items records so // that subsequent calculations will use the adjusted grademin and grademax. $grade_items[$do]->grademin = $adjustedgrade['grademin']; $grade_items[$do]->grademax = $adjustedgrade['grademax']; $altered[$do] = $finalgrade; unset($todo[$key]); $found = true; continue; } } } } } if (!$found) { break; } } return array('unknown' => $unknown, 'altered' => $altered, 'alteredgrademax' => $alteredgrademax, 'alteredgrademin' => $alteredgrademin, 'alteredaggregationstatus' => $alteredaggregationstatus, 'alteredaggregationweight' => $alteredaggregationweight); }
protected function generate_random_raw_grade($item, $userid) { $grade = new grade_grade(); $grade->itemid = $item->id; $grade->userid = $userid; $grade->grademin = 0; $grade->grademax = 1; $valuetype = "grade{$item->gradetype}"; $grade->rawgrade = rand(0, 1000) / 1000; $grade->insert(); return $grade->rawgrade; }
/** * Return standard meta data for module * * @param cm_info $mod * @param string $timeopenfld * @param string $timeclosefld * @param string $keyfield * @param string $submissiontable * @param string $submittedonfld * @param string $submitstrkey * @param bool $isgradeable * @param string $submitselect - sql to further filter submission row select statement - e.g. st.status='finished' * @return bool | \theme_snap\activity_meta */ protected static function std_meta(\cm_info $mod, $timeopenfld, $timeclosefld, $keyfield, $submissiontable, $submittedonfld, $submitstrkey, $isgradeable = false, $submitselect = '') { global $USER; $courseid = $mod->course; // Create meta data object. $meta = new \theme_snap\activity_meta(); $meta->submitstrkey = $submitstrkey; $meta->submittedstr = get_string($submitstrkey, 'theme_snap'); $meta->notsubmittedstr = get_string('not' . $submitstrkey, 'theme_snap'); if (get_string_manager()->string_exists($mod->modname . 'draft', 'theme_snap')) { $meta->draftstr = get_string($mod->modname . 'draft', 'theme_snap'); } else { $meta->drafstr = get_string('draft', 'theme_snap'); } if (get_string_manager()->string_exists($mod->modname . 'reopened', 'theme_snap')) { $meta->reopenedstr = get_string($mod->modname . 'reopened', 'theme_snap'); } else { $meta->reopenedstr = get_string('reopened', 'theme_snap'); } // If module is not visible to the user then don't bother getting meta data. if (!$mod->uservisible) { return $meta; } $activitydates = self::instance_activity_dates($courseid, $mod, $timeopenfld, $timeclosefld); $meta->timeopen = $activitydates->timeopen; $meta->timeclose = $activitydates->timeclose; // TODO: use activity specific "teacher" capabilities. if (has_capability('mod/assign:grade', \context_course::instance($courseid))) { $meta->isteacher = true; // Teacher - useful teacher meta data. $methodnsubmissions = $mod->modname . '_num_submissions'; $methodnungraded = $mod->modname . '_num_submissions_ungraded'; if (method_exists('theme_snap\\activity', $methodnsubmissions)) { $meta->numsubmissions = call_user_func('theme_snap\\activity::' . $methodnsubmissions, $courseid, $mod->instance); } if (method_exists('theme_snap\\activity', $methodnungraded)) { $meta->numrequiregrading = call_user_func('theme_snap\\activity::' . $methodnungraded, $courseid, $mod->instance); } } else { // Student - useful student meta data - only display if activity is available. if (empty($activitydates->timeopen) || usertime($activitydates->timeopen) <= time()) { $submissionrow = self::get_submission_row($courseid, $mod, $submissiontable, $keyfield, $submitselect); if (!empty($submissionrow)) { if ($submissionrow->status) { switch ($submissionrow->status) { case 'draft': $meta->draft = true; break; case 'reopened': $meta->reopened = true; break; case 'submitted': $meta->submitted = true; break; } } else { $meta->submitted = true; $meta->timesubmitted = !empty($submissionrow->{$submittedonfld}) ? $submissionrow->{$submittedonfld} : null; } // If submitted on field uses modified field then fall back to timecreated if modified is 0. if (empty($meta->timesubmitted) && ($submittedonfld = 'timemodified')) { if (isset($submissionrow->timemodified)) { $meta->timesubmitted = $submissionrow->timemodified; } else { $meta->timesubmitted = $submissionrow->timecreated; } } } } $graderow = false; if ($isgradeable) { $graderow = self::grade_row($courseid, $mod); } if ($graderow) { $gradeitem = \grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => $mod->modname, 'iteminstance' => $mod->instance)); $grade = new \grade_grade(array('itemid' => $gradeitem->id, 'userid' => $USER->id)); $coursecontext = \context_course::instance($courseid); $canviewhiddengrade = has_capability('moodle/grade:viewhidden', $coursecontext); if (!$grade->is_hidden() || $canviewhiddengrade) { $meta->grade = true; } } } return $meta; }
/** * Marks user deleted in internal user database and notifies the auth plugin. * Also unenrols user from all roles and does other cleanup. * @param object $user Userobject before delete (without system magic quotes) * @return boolean success */ function delete_user($user) { global $CFG; require_once $CFG->libdir . '/grouplib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/message/lib.php'; begin_sql(); // delete all grades - backup is kept in grade_grades_history table if ($grades = grade_grade::fetch_all(array('userid' => $user->id))) { foreach ($grades as $grade) { $grade->delete('userdelete'); } } //move unread messages from this user to read message_move_userfrom_unread2read($user->id); // remove from all groups delete_records('groups_members', 'userid', $user->id); // unenrol from all roles in all contexts role_unassign(0, $user->id); // this might be slow but it is really needed - modules might do some extra cleanup! // now do a final accesslib cleanup - removes all role assingments in user context and context itself delete_context(CONTEXT_USER, $user->id); require_once $CFG->dirroot . '/tag/lib.php'; tag_set('user', $user->id, array()); // workaround for bulk deletes of users with the same email address $delname = addslashes("{$user->email}." . time()); while (record_exists('user', 'username', $delname)) { // no need to use mnethostid here $delname++; } // mark internal user record as "deleted" $updateuser = new object(); $updateuser->id = $user->id; $updateuser->deleted = 1; $updateuser->username = $delname; // Remember it just in case $updateuser->email = md5($user->username); // Store hash of username, useful importing/restoring users $updateuser->idnumber = ''; // Clear this field to free it up $updateuser->timemodified = time(); if (update_record('user', $updateuser)) { commit_sql(); // notify auth plugin - do not block the delete even when plugin fails $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); events_trigger('user_deleted', $user); return true; } else { rollback_sql(); return false; } }
//$users = $report_evalcomix->load_users(); //$finalgrades = $report_evalcomix->get_grades(); $numpages = (int) ($numusers / $studentsperpage); if ($numusers % $studentsperpage > 0) { $numpages += 1; } for ($ipage = 0; $ipage < $numpages; ++$ipage) { $report_grader = new grade_report_grader($courseid, null, $context, $ipage, $sortitemid); $report_grader->load_users(); $report_grader->load_final_grades(); foreach ($report_grader->users as $userid => $user) { if ($report_grader->canviewhidden) { $altered = array(); $unknown = array(); } else { $hidingaffected = grade_grade::get_hiding_affected($report_grader->grades[$userid], $report_grader->gtree->get_items()); $altered = $hidingaffected['altered']; $unknown = $hidingaffected['unknown']; unset($hidingaffected); } foreach ($report_grader->gtree->items as $itemid => $unused) { $item =& $report_grader->gtree->items[$itemid]; $grade = $report_grader->grades[$userid][$item->id]; // Get the decimal points preference for this item $decimalpoints = $item->get_decimals(); if (in_array($itemid, $unknown)) { $gradeval = null; } else { if (array_key_exists($itemid, $altered)) { $gradeval = $altered[$itemid]; } else {
/** * Grading cron job */ function grade_cron() { global $CFG; $now = time(); $sql = "SELECT i.*\n FROM {$CFG->prefix}grade_items i\n WHERE i.locked = 0 AND i.locktime > 0 AND i.locktime < {$now} AND EXISTS (\n SELECT 'x' FROM {$CFG->prefix}grade_items c WHERE c.itemtype='course' AND c.needsupdate=0 AND c.courseid=i.courseid)"; // go through all courses that have proper final grades and lock them if needed if ($rs = get_recordset_sql($sql)) { if ($rs->RecordCount() > 0) { while ($item = rs_fetch_next_record($rs)) { $grade_item = new grade_item($item, false); $grade_item->locked = $now; $grade_item->update('locktime'); } } rs_close($rs); } $grade_inst = new grade_grade(); $fields = 'g.' . implode(',g.', $grade_inst->required_fields); $sql = "SELECT {$fields}\n FROM {$CFG->prefix}grade_grades g, {$CFG->prefix}grade_items i\n WHERE g.locked = 0 AND g.locktime > 0 AND g.locktime < {$now} AND g.itemid=i.id AND EXISTS (\n SELECT 'x' FROM {$CFG->prefix}grade_items c WHERE c.itemtype='course' AND c.needsupdate=0 AND c.courseid=i.courseid)"; // go through all courses that have proper final grades and lock them if needed if ($rs = get_recordset_sql($sql)) { if ($rs->RecordCount() > 0) { while ($grade = rs_fetch_next_record($rs)) { $grade_grade = new grade_grade($grade, false); $grade_grade->locked = $now; $grade_grade->update('locktime'); } } rs_close($rs); } }
function definition_after_data() { global $CFG, $COURSE, $DB; $context = context_course::instance($COURSE->id); $mform =& $this->_form; $grade_item = $this->_customdata['grade_item']; // fill in user name if user still exists $userid = $mform->getElementValue('userid'); if ($user = $DB->get_record('user', array('id' => $userid))) { $username = '******' . $CFG->wwwroot . '/user/view.php?id=' . $userid . '">' . fullname($user) . '</a>'; $user_el =& $mform->getElement('user'); $user_el->setValue($username); } // add activity name + link 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); // access control - disable not allowed elements if (!has_capability('moodle/grade:manage', $context)) { $mform->hardFreeze('excluded'); } if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:hide', $context)) { $mform->hardFreeze('hidden'); $mform->hardFreeze('hiddenuntil'); } $old_grade_grade = new grade_grade(array('itemid' => $grade_item->id, 'userid' => $userid)); if (!$grade_item->is_overridable_item()) { $mform->removeElement('overridden'); } if ($grade_item->is_hidden()) { $mform->hardFreeze('hidden'); } 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; } 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'); } } } }
import_cleanup($importcode); echo $OUTPUT->notification('user mapping error, could not find user!'); break; } if ($separatemode and !groups_is_member($currentgroup, $studentid)) { // not allowed to import into this group, abort $status = false; import_cleanup($importcode); echo $OUTPUT->notification('user not member of current group, can not update!'); break; } // insert results of this students into buffer if ($status and !empty($newgrades)) { foreach ($newgrades as $newgrade) { // check if grade_grade is locked and if so, abort if (!empty($newgrade->itemid) and $grade_grade = new grade_grade(array('itemid' => $newgrade->itemid, 'userid' => $studentid))) { if ($grade_grade->is_locked()) { // individual grade locked $status = false; import_cleanup($importcode); echo $OUTPUT->notification(get_string('gradelocked', 'grades')); break 2; } } $newgrade->importcode = $importcode; $newgrade->userid = $studentid; $newgrade->importer = $USER->id; $DB->insert_record('grade_import_values', $newgrade); } } // updating/inserting all comments here
/** * internal function - does the final grade calculation */ function use_formula($userid, $params, $useditems, $oldgrade) { if (empty($userid)) { return true; } // add missing final grade values // not graded (null) is counted as 0 - the spreadsheet way foreach ($useditems as $gi) { if (!array_key_exists('gi' . $gi, $params)) { $params['gi' . $gi] = 0; } else { $params['gi' . $gi] = (double) $params['gi' . $gi]; } } // can not use own final grade during calculation unset($params['gi' . $this->id]); // insert final grade - will be needed later anyway if ($oldgrade) { $oldfinalgrade = $oldgrade->finalgrade; $grade = new grade_grade($oldgrade, false); // fetching from db is not needed $grade->grade_item =& $this; } else { $grade = new grade_grade(array('itemid' => $this->id, 'userid' => $userid), false); $grade->grade_item =& $this; $grade->insert('system'); $oldfinalgrade = null; } // no need to recalculate locked or overridden grades if ($grade->is_locked() or $grade->is_overridden()) { return true; } // do the calculation $this->formula->set_params($params); $result = $this->formula->evaluate(); if ($result === false) { $grade->finalgrade = null; } else { // normalize $result = bounded_number($this->grademin, $result, $this->grademax); if ($this->gradetype == GRADE_TYPE_SCALE) { $result = round($result + 1.0E-5); // round scales upwards } $grade->finalgrade = $result; } // update in db if changed if (grade_floats_different($grade->finalgrade, $oldfinalgrade)) { $grade->update('compute'); } if ($result !== false) { //lock grade if needed } if ($result === false) { return false; } else { return true; } }
public function fill_table() { global $CFG, $DB; // MDL-11679, only show 'mycourses' instead of all courses if ($courses = get_my_courses($this->user->id, 'c.sortorder ASC', 'id, shortname, showgrades')) { $numusers = $this->get_numusers(false); foreach ($courses as $course) { if (!$course->showgrades) { continue; } $courselink = '<a href="' . $CFG->wwwroot . '/grade/report/user/index.php?id=' . $course->id . '">' . $course->shortname . '</a>'; $canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $course->id)); // Get course grade_item $course_item = grade_item::fetch_course_item($course->id); // Get the stored grade $course_grade = new grade_grade(array('itemid' => $course_item->id, 'userid' => $this->user->id)); $course_grade->grade_item =& $course_item; $finalgrade = $course_grade->finalgrade; if (!$canviewhidden and !is_null($finalgrade)) { if ($course_grade->is_hidden()) { $finalgrade = null; } else { // This is a really ugly hack, it will be fixed in 2.0 $items = grade_item::fetch_all(array('courseid' => $course->id)); $grades = array(); $sql = "SELECT g.*\n FROM {grade_grades} g\n JOIN {grade_items} gi ON gi.id = g.itemid\n WHERE g.userid = ? AND gi.courseid = ?"; if ($gradesrecords = $DB->get_records_sql($sql, array($this->user->id, $course->id))) { foreach ($gradesrecords as $grade) { $grades[$grade->itemid] = new grade_grade($grade, false); } unset($gradesrecords); } foreach ($items as $itemid => $unused) { if (!isset($grades[$itemid])) { $grade_grade = new grade_grade(); $grade_grade->userid = $this->user->id; $grade_grade->itemid = $items[$itemid]->id; $grades[$itemid] = $grade_grade; } $grades[$itemid]->grade_item =& $items[$itemid]; } $hiding_affected = grade_grade::get_hiding_affected($grades, $items); if (array_key_exists($course_item->id, $hiding_affected['altered'])) { $finalgrade = $hiding_affected['altered'][$course_item->id]; } else { if (!empty($hiding_affected['unknown'][$course_item->id])) { $finalgrade = null; } } unset($hiding_affected); unset($grades); unset($items); } } $data = array($courselink, grade_format_gradevalue($finalgrade, $course_item, true)); if (!$this->showrank) { //nothing to do } else { if (!is_null($finalgrade)) { /// find the number of users with a higher grade /// please note this can not work if hidden grades involved :-( to be fixed in 2.0 $params = array($finalgrade, $course_item->id); $sql = "SELECT COUNT(DISTINCT(userid))\n FROM {grade_grades}\n WHERE finalgrade IS NOT NULL AND finalgrade > ?\n AND itemid = ?"; $rank = $DB->count_records_sql($sql, $params) + 1; $data[] = "{$rank}/{$numusers}"; } else { // no grade, no rank $data[] = '-'; } } $this->table->add_data($data); } return true; } else { notify(get_string('nocourses', 'grades')); return false; } }
/** * Optionally blank out course/category totals if they contain any hidden items * @param string $courseid the course id * @param string $course_item an instance of grade_item * @param string $finalgrade the grade for the course_item * @return string The new final grade */ protected function blank_hidden_total($courseid, $course_item, $finalgrade) { global $CFG, $DB; static $hiding_affected = null; //array of items in this course affected by hiding // If we're dealing with multiple users we need to know when we've moved on to a new user. static $previous_userid = null; // If we're dealing with multiple courses we need to know when we've moved on to a new course. static $previous_courseid = null; if (!is_array($this->showtotalsifcontainhidden)) { debugging('showtotalsifcontainhidden should be an array', DEBUG_DEVELOPER); $this->showtotalsifcontainhidden = array($courseid => $this->showtotalsifcontainhidden); } if ($this->showtotalsifcontainhidden[$courseid] == GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN) { return $finalgrade; } // If we've moved on to another course or user, reload the grades. if ($previous_userid != $this->user->id || $previous_courseid != $courseid) { $hiding_affected = null; $previous_userid = $this->user->id; $previous_courseid = $courseid; } if (!$hiding_affected) { $items = grade_item::fetch_all(array('courseid' => $courseid)); $grades = array(); $sql = "SELECT g.*\n FROM {grade_grades} g\n JOIN {grade_items} gi ON gi.id = g.itemid\n WHERE g.userid = {$this->user->id} AND gi.courseid = {$courseid}"; if ($gradesrecords = $DB->get_records_sql($sql)) { foreach ($gradesrecords as $grade) { $grades[$grade->itemid] = new grade_grade($grade, false); } unset($gradesrecords); } foreach ($items as $itemid => $unused) { if (!isset($grades[$itemid])) { $grade_grade = new grade_grade(); $grade_grade->userid = $this->user->id; $grade_grade->itemid = $items[$itemid]->id; $grades[$itemid] = $grade_grade; } $grades[$itemid]->grade_item =& $items[$itemid]; } $hiding_affected = grade_grade::get_hiding_affected($grades, $items); } //if the item definitely depends on a hidden item if (array_key_exists($course_item->id, $hiding_affected['altered'])) { if (!$this->showtotalsifcontainhidden[$courseid]) { //hide the grade $finalgrade = null; } else { //use reprocessed marks that exclude hidden items $finalgrade = $hiding_affected['altered'][$course_item->id]; } } else { if (!empty($hiding_affected['unknown'][$course_item->id])) { //not sure whether or not this item depends on a hidden item if (!$this->showtotalsifcontainhidden[$courseid]) { //hide the grade $finalgrade = null; } else { //use reprocessed marks that exclude hidden items $finalgrade = $hiding_affected['unknown'][$course_item->id]; } } } return $finalgrade; }
/** * Calculates the completion state for an activity and user. * * Internal function. Not private, so we can unit-test it. * * @param stdClass|cm_info $cm Activity * @param int $userid ID of user * @param stdClass $current Previous completion information from database * @return mixed */ public function internal_get_state($cm, $userid, $current) { global $USER, $DB, $CFG; // Get user ID if (!$userid) { $userid = $USER->id; } // Check viewed if ($cm->completionview == COMPLETION_VIEW_REQUIRED && $current->viewed == COMPLETION_NOT_VIEWED) { return COMPLETION_INCOMPLETE; } // Modname hopefully is provided in $cm but just in case it isn't, let's grab it if (!isset($cm->modname)) { $cm->modname = $DB->get_field('modules', 'name', array('id' => $cm->module)); } $newstate = COMPLETION_COMPLETE; // Check grade if (!is_null($cm->completiongradeitemnumber)) { require_once $CFG->libdir . '/gradelib.php'; $item = grade_item::fetch(array('courseid' => $cm->course, 'itemtype' => 'mod', 'itemmodule' => $cm->modname, 'iteminstance' => $cm->instance, 'itemnumber' => $cm->completiongradeitemnumber)); if ($item) { // Fetch 'grades' (will be one or none) $grades = grade_grade::fetch_users_grades($item, array($userid), false); if (empty($grades)) { // No grade for user return COMPLETION_INCOMPLETE; } if (count($grades) > 1) { $this->internal_systemerror("Unexpected result: multiple grades for\n item '{$item->id}', user '{$userid}'"); } $newstate = self::internal_get_grade_state($item, reset($grades)); if ($newstate == COMPLETION_INCOMPLETE) { return COMPLETION_INCOMPLETE; } } else { $this->internal_systemerror("Cannot find grade item for '{$cm->modname}'\n cm '{$cm->id}' matching number '{$cm->completiongradeitemnumber}'"); } } if (plugin_supports('mod', $cm->modname, FEATURE_COMPLETION_HAS_RULES)) { $function = $cm->modname . '_get_completion_state'; if (!function_exists($function)) { $this->internal_systemerror("Module {$cm->modname} claims to support\n FEATURE_COMPLETION_HAS_RULES but does not have required\n {$cm->modname}_get_completion_state function"); } if (!$function($this->course, $cm, $userid, COMPLETION_AND)) { return COMPLETION_INCOMPLETE; } } return $newstate; }
/** * Returns the aggregated or calculated course grade for the given user(s). * @public * @param int $userid * @param int $courseid optional id of course or array of ids, empty means all uses courses (returns array if not present) * @return mixed grade info or grades array including item info, false if error */ function grade_get_course_grade($userid, $courseid_or_ids = null) { if (!is_array($courseid_or_ids)) { if (empty($courseid_or_ids)) { if (!($courses = enrol_get_users_courses($userid))) { return false; } $courseids = array_keys($courses); return grade_get_course_grade($userid, $courseids); } if (!is_numeric($courseid_or_ids)) { return false; } if (!($grades = grade_get_course_grade($userid, array($courseid_or_ids)))) { return false; } else { // only one grade - not array $grade = reset($grades); return $grade; } } foreach ($courseid_or_ids as $courseid) { $grade_item = grade_item::fetch_course_item($courseid); $course_items[$grade_item->courseid] = $grade_item; } $grades = array(); foreach ($course_items as $grade_item) { if ($grade_item->needsupdate) { grade_regrade_final_grades($courseid); } $item = new stdClass(); $item->scaleid = $grade_item->scaleid; $item->name = $grade_item->get_name(); $item->grademin = $grade_item->grademin; $item->grademax = $grade_item->grademax; $item->gradepass = $grade_item->gradepass; $item->locked = $grade_item->is_locked(); $item->hidden = $grade_item->is_hidden(); switch ($grade_item->gradetype) { case GRADE_TYPE_NONE: continue; case GRADE_TYPE_VALUE: $item->scaleid = 0; break; case GRADE_TYPE_TEXT: $item->scaleid = 0; $item->grademin = 0; $item->grademax = 0; $item->gradepass = 0; break; } $grade_grade = new grade_grade(array('userid' => $userid, 'itemid' => $grade_item->id)); $grade_grade->grade_item =& $grade_item; $grade = new stdClass(); $grade->grade = $grade_grade->finalgrade; $grade->locked = $grade_grade->is_locked(); $grade->hidden = $grade_grade->is_hidden(); $grade->overridden = $grade_grade->overridden; $grade->feedback = $grade_grade->feedback; $grade->feedbackformat = $grade_grade->feedbackformat; $grade->usermodified = $grade_grade->usermodified; $grade->dategraded = $grade_grade->get_dategraded(); $grade->item = $item; // create text representation of grade if ($grade_item->needsupdate) { $grade->grade = false; $grade->str_grade = get_string('error'); $grade->str_long_grade = $grade->str_grade; } else { if (is_null($grade->grade)) { $grade->str_grade = '-'; $grade->str_long_grade = $grade->str_grade; } else { $grade->str_grade = grade_format_gradevalue($grade->grade, $grade_item); if ($grade_item->gradetype == GRADE_TYPE_SCALE or $grade_item->get_displaytype() != GRADE_DISPLAY_TYPE_REAL) { $grade->str_long_grade = $grade->str_grade; } else { $a = new stdClass(); $a->grade = $grade->str_grade; $a->max = grade_format_gradevalue($grade_item->grademax, $grade_item); $grade->str_long_grade = get_string('gradelong', 'grades', $a); } } } // create html representation of feedback if (is_null($grade->feedback)) { $grade->str_feedback = ''; } else { $grade->str_feedback = format_text($grade->feedback, $grade->feedbackformat); } $grades[$grade_item->courseid] = $grade; } return $grades; }
protected function process_grade_grade($data) { $data = (object) $data; $olduserid = $data->userid; unset($data->id); $data->itemid = $this->get_new_parentid('grade_item'); $data->userid = $this->get_mappingid('user', $data->userid, null); if (!empty($data->userid)) { $data->usermodified = $this->get_mappingid('user', $data->usermodified, null); $data->rawscaleid = $this->get_mappingid('scale', $data->rawscaleid); // TODO: Ask, all the rest of locktime/exported... work with time... to be rolled? $data->overridden = $this->apply_date_offset($data->overridden); $grade = new grade_grade($data, false); $grade->insert('restore'); // no need to save any grade_grade mapping } else { debugging("Mapped user id not found for user id '{$olduserid}', grade item id '{$data->itemid}'"); } }
/** * This function creates all the gradebook data from xml */ function restore_create_gradebook($restore, $xml_file) { global $CFG; $status = true; //Check it exists if (!file_exists($xml_file)) { return false; } // Get info from xml // info will contain the number of record to process $info = restore_read_xml_gradebook($restore, $xml_file); // If we have info, then process if (empty($info)) { return $status; } if (empty($CFG->disablegradehistory) and isset($info->gradebook_histories) and $info->gradebook_histories == "true") { $restore_histories = true; } else { $restore_histories = false; } // make sure top course category exists $course_category = grade_category::fetch_course_category($restore->course_id); $course_category->load_grade_item(); // we need to know if all grade items that were backed up are being restored // if that is not the case, we do not restore grade categories nor gradeitems of category type or course type // i.e. the aggregated grades of that category $restoreall = true; // set to false if any grade_item is not selected/restored or already exist $importing = !empty($SESSION->restore->importing); if ($importing) { $restoreall = false; } else { $prev_grade_items = grade_item::fetch_all(array('courseid' => $restore->course_id)); $prev_grade_cats = grade_category::fetch_all(array('courseid' => $restore->course_id)); // if any categories already present, skip restore of categories from backup - course item or category already exist if (count($prev_grade_items) > 1 or count($prev_grade_cats) > 1) { $restoreall = false; } unset($prev_grade_items); unset($prev_grade_cats); if ($restoreall) { if ($recs = get_records_select("backup_ids", "table_name = 'grade_items' AND backup_code = {$restore->backup_unique_code}", "", "old_id")) { foreach ($recs as $rec) { if ($data = backup_getid($restore->backup_unique_code, 'grade_items', $rec->old_id)) { $info = $data->info; // do not restore if this grade_item is a mod, and $itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#']); if ($itemtype == 'mod') { $olditeminstance = backup_todb($info['GRADE_ITEM']['#']['ITEMINSTANCE']['0']['#']); $itemmodule = backup_todb($info['GRADE_ITEM']['#']['ITEMMODULE']['0']['#']); if (empty($restore->mods[$itemmodule]->granular)) { continue; } else { if (!empty($restore->mods[$itemmodule]->instances[$olditeminstance]->restore)) { continue; } } // at least one activity should not be restored - do not restore categories and manual items at all $restoreall = false; break; } } } } } } // Start ul if (!defined('RESTORE_SILENTLY')) { echo '<ul>'; } // array of restored categories - speedup ;-) $cached_categories = array(); $outcomes = array(); /// Process letters $context = get_context_instance(CONTEXT_COURSE, $restore->course_id); // respect current grade letters if defined if ($status and $restoreall and !record_exists('grade_letters', 'contextid', $context->id)) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeletters', 'grades') . '</li>'; } // Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_letters' AND backup_code = {$restore->backup_unique_code}", "", "old_id"); if ($recs) { foreach ($recs as $rec) { // Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_letters', $rec->old_id); if ($data) { $info = $data->info; $dbrec = new object(); $dbrec->contextid = $context->id; $dbrec->lowerboundary = backup_todb($info['GRADE_LETTER']['#']['LOWERBOUNDARY']['0']['#']); $dbrec->letter = backup_todb($info['GRADE_LETTER']['#']['LETTER']['0']['#']); insert_record('grade_letters', $dbrec); } } } } /// Preprocess outcomes - do not store them yet! if ($status and !$importing and $restoreall) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeoutcomes', 'grades') . '</li>'; } $recs = get_records_select("backup_ids", "table_name = 'grade_outcomes' AND backup_code = '{$restore->backup_unique_code}'", "", "old_id"); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_outcomes', $rec->old_id); if ($data) { $info = $data->info; //first find out if outcome already exists $shortname = backup_todb($info['GRADE_OUTCOME']['#']['SHORTNAME']['0']['#']); if ($candidates = get_records_sql("SELECT *\n FROM {$CFG->prefix}grade_outcomes\n WHERE (courseid IS NULL OR courseid = {$restore->course_id})\n AND shortname = '{$shortname}'\n ORDER BY courseid ASC, id ASC")) { $grade_outcome = reset($candidates); $outcomes[$rec->old_id] = $grade_outcome; continue; } $dbrec = new object(); if (has_capability('moodle/grade:manageoutcomes', get_context_instance(CONTEXT_SYSTEM))) { $oldoutcome = backup_todb($info['GRADE_OUTCOME']['#']['COURSEID']['0']['#']); if (empty($oldoutcome)) { //site wide $dbrec->courseid = null; } else { //course only $dbrec->courseid = $restore->course_id; } } else { // no permission to add site outcomes $dbrec->courseid = $restore->course_id; } //Get the fields $dbrec->shortname = backup_todb($info['GRADE_OUTCOME']['#']['SHORTNAME']['0']['#'], false); $dbrec->fullname = backup_todb($info['GRADE_OUTCOME']['#']['FULLNAME']['0']['#'], false); $dbrec->scaleid = backup_todb($info['GRADE_OUTCOME']['#']['SCALEID']['0']['#'], false); $dbrec->description = backup_todb($info['GRADE_OUTCOME']['#']['DESCRIPTION']['0']['#'], false); $dbrec->timecreated = backup_todb($info['GRADE_OUTCOME']['#']['TIMECREATED']['0']['#'], false); $dbrec->timemodified = backup_todb($info['GRADE_OUTCOME']['#']['TIMEMODIFIED']['0']['#'], false); $dbrec->usermodified = backup_todb($info['GRADE_OUTCOME']['#']['USERMODIFIED']['0']['#'], false); //Need to recode the scaleid if ($scale = backup_getid($restore->backup_unique_code, 'scale', $dbrec->scaleid)) { $dbrec->scaleid = $scale->new_id; } //Need to recode the usermodified if ($modifier = backup_getid($restore->backup_unique_code, 'user', $dbrec->usermodified)) { $dbrec->usermodified = $modifier->new_id; } $grade_outcome = new grade_outcome($dbrec, false); $outcomes[$rec->old_id] = $grade_outcome; } } } } /// Process grade items and grades if ($status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeitems', 'grades') . '</li>'; } $counter = 0; //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_items' AND backup_code = '{$restore->backup_unique_code}'", "id", "old_id"); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_items', $rec->old_id); if ($data) { $info = $data->info; // first find out if category or normal item $itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#'], false); if ($itemtype == 'course' or $itemtype == 'category') { if (!$restoreall or $importing) { continue; } $oldcat = backup_todb($info['GRADE_ITEM']['#']['ITEMINSTANCE']['0']['#'], false); if (!($cdata = backup_getid($restore->backup_unique_code, 'grade_categories', $oldcat))) { continue; } $cinfo = $cdata->info; unset($cdata); if ($itemtype == 'course') { $course_category->fullname = backup_todb($cinfo['GRADE_CATEGORY']['#']['FULLNAME']['0']['#'], false); $course_category->aggregation = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATION']['0']['#'], false); $course_category->keephigh = backup_todb($cinfo['GRADE_CATEGORY']['#']['KEEPHIGH']['0']['#'], false); $course_category->droplow = backup_todb($cinfo['GRADE_CATEGORY']['#']['DROPLOW']['0']['#'], false); $course_category->aggregateonlygraded = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEONLYGRADED']['0']['#'], false); $course_category->aggregateoutcomes = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEOUTCOMES']['0']['#'], false); $course_category->aggregatesubcats = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATESUBCATS']['0']['#'], false); $course_category->timecreated = backup_todb($cinfo['GRADE_CATEGORY']['#']['TIMECREATED']['0']['#'], false); $course_category->update('restore'); $status = backup_putid($restore->backup_unique_code, 'grade_categories', $oldcat, $course_category->id) && $status; $cached_categories[$oldcat] = $course_category; $grade_item = $course_category->get_grade_item(); } else { $oldparent = backup_todb($cinfo['GRADE_CATEGORY']['#']['PARENT']['0']['#'], false); if (empty($cached_categories[$oldparent])) { debugging('parent not found ' . $oldparent); continue; // parent not found, sorry } $grade_category = new grade_category(); $grade_category->courseid = $restore->course_id; $grade_category->parent = $cached_categories[$oldparent]->id; $grade_category->fullname = backup_todb($cinfo['GRADE_CATEGORY']['#']['FULLNAME']['0']['#'], false); $grade_category->aggregation = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATION']['0']['#'], false); $grade_category->keephigh = backup_todb($cinfo['GRADE_CATEGORY']['#']['KEEPHIGH']['0']['#'], false); $grade_category->droplow = backup_todb($cinfo['GRADE_CATEGORY']['#']['DROPLOW']['0']['#'], false); $grade_category->aggregateonlygraded = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEONLYGRADED']['0']['#'], false); $grade_category->aggregateoutcomes = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEOUTCOMES']['0']['#'], false); $grade_category->aggregatesubcats = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATESUBCATS']['0']['#'], false); $grade_category->timecreated = backup_todb($cinfo['GRADE_CATEGORY']['#']['TIMECREATED']['0']['#'], false); $grade_category->insert('restore'); $status = backup_putid($restore->backup_unique_code, 'grade_categories', $oldcat, $grade_category->id) && $status; $cached_categories[$oldcat] = $grade_category; $grade_item = $grade_category->get_grade_item(); // creates grade_item too } unset($cinfo); $idnumber = backup_todb($info['GRADE_ITEM']['#']['IDNUMBER']['0']['#'], false); if (grade_verify_idnumber($idnumber, $restore->course_id)) { $grade_item->idnumber = $idnumber; } $grade_item->itemname = backup_todb($info['GRADE_ITEM']['#']['ITEMNAME']['0']['#'], false); $grade_item->iteminfo = backup_todb($info['GRADE_ITEM']['#']['ITEMINFO']['0']['#'], false); $grade_item->gradetype = backup_todb($info['GRADE_ITEM']['#']['GRADETYPE']['0']['#'], false); $grade_item->calculation = backup_todb($info['GRADE_ITEM']['#']['CALCULATION']['0']['#'], false); $grade_item->grademax = backup_todb($info['GRADE_ITEM']['#']['GRADEMAX']['0']['#'], false); $grade_item->grademin = backup_todb($info['GRADE_ITEM']['#']['GRADEMIN']['0']['#'], false); $grade_item->gradepass = backup_todb($info['GRADE_ITEM']['#']['GRADEPASS']['0']['#'], false); $grade_item->multfactor = backup_todb($info['GRADE_ITEM']['#']['MULTFACTOR']['0']['#'], false); $grade_item->plusfactor = backup_todb($info['GRADE_ITEM']['#']['PLUSFACTOR']['0']['#'], false); $grade_item->aggregationcoef = backup_todb($info['GRADE_ITEM']['#']['AGGREGATIONCOEF']['0']['#'], false); $grade_item->display = backup_todb($info['GRADE_ITEM']['#']['DISPLAY']['0']['#'], false); $grade_item->decimals = backup_todb($info['GRADE_ITEM']['#']['DECIMALS']['0']['#'], false); $grade_item->hidden = backup_todb($info['GRADE_ITEM']['#']['HIDDEN']['0']['#'], false); $grade_item->locked = backup_todb($info['GRADE_ITEM']['#']['LOCKED']['0']['#'], false); $grade_item->locktime = backup_todb($info['GRADE_ITEM']['#']['LOCKTIME']['0']['#'], false); $grade_item->timecreated = backup_todb($info['GRADE_ITEM']['#']['TIMECREATED']['0']['#'], false); if (backup_todb($info['GRADE_ITEM']['#']['SCALEID']['0']['#'], false)) { $scale = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_ITEM']['#']['SCALEID']['0']['#'], false)); $grade_item->scaleid = $scale->new_id; } if (backup_todb($info['GRADE_ITEM']['#']['OUTCOMEID']['0']['#'], false)) { $outcome = backup_getid($restore->backup_unique_code, "grade_outcomes", backup_todb($info['GRADE_ITEM']['#']['OUTCOMEID']['0']['#'], false)); $grade_item->outcomeid = $outcome->new_id; } $grade_item->update('restore'); $status = backup_putid($restore->backup_unique_code, "grade_items", $rec->old_id, $grade_item->id) && $status; } else { if ($itemtype != 'mod' and (!$restoreall or $importing)) { // not extra gradebook stuff if restoring individual activities or something already there continue; } $dbrec = new object(); $dbrec->courseid = $restore->course_id; $dbrec->itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#'], false); $dbrec->itemmodule = backup_todb($info['GRADE_ITEM']['#']['ITEMMODULE']['0']['#'], false); if ($itemtype == 'mod') { // iteminstance should point to new mod $olditeminstance = backup_todb($info['GRADE_ITEM']['#']['ITEMINSTANCE']['0']['#'], false); $mod = backup_getid($restore->backup_unique_code, $dbrec->itemmodule, $olditeminstance); $dbrec->iteminstance = $mod->new_id; if (!($cm = get_coursemodule_from_instance($dbrec->itemmodule, $mod->new_id))) { // item not restored - no item continue; } // keep in sync with activity idnumber $dbrec->idnumber = $cm->idnumber; } else { $idnumber = backup_todb($info['GRADE_ITEM']['#']['IDNUMBER']['0']['#'], false); if (grade_verify_idnumber($idnumber, $restore->course_id)) { //make sure the new idnumber is unique $dbrec->idnumber = $idnumber; } } $dbrec->itemname = backup_todb($info['GRADE_ITEM']['#']['ITEMNAME']['0']['#'], false); $dbrec->itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#'], false); $dbrec->itemmodule = backup_todb($info['GRADE_ITEM']['#']['ITEMMODULE']['0']['#'], false); $dbrec->itemnumber = backup_todb($info['GRADE_ITEM']['#']['ITEMNUMBER']['0']['#'], false); $dbrec->iteminfo = backup_todb($info['GRADE_ITEM']['#']['ITEMINFO']['0']['#'], false); $dbrec->gradetype = backup_todb($info['GRADE_ITEM']['#']['GRADETYPE']['0']['#'], false); $dbrec->calculation = backup_todb($info['GRADE_ITEM']['#']['CALCULATION']['0']['#'], false); $dbrec->grademax = backup_todb($info['GRADE_ITEM']['#']['GRADEMAX']['0']['#'], false); $dbrec->grademin = backup_todb($info['GRADE_ITEM']['#']['GRADEMIN']['0']['#'], false); $dbrec->gradepass = backup_todb($info['GRADE_ITEM']['#']['GRADEPASS']['0']['#'], false); $dbrec->multfactor = backup_todb($info['GRADE_ITEM']['#']['MULTFACTOR']['0']['#'], false); $dbrec->plusfactor = backup_todb($info['GRADE_ITEM']['#']['PLUSFACTOR']['0']['#'], false); $dbrec->aggregationcoef = backup_todb($info['GRADE_ITEM']['#']['AGGREGATIONCOEF']['0']['#'], false); $dbrec->display = backup_todb($info['GRADE_ITEM']['#']['DISPLAY']['0']['#'], false); $dbrec->decimals = backup_todb($info['GRADE_ITEM']['#']['DECIMALS']['0']['#'], false); $dbrec->hidden = backup_todb($info['GRADE_ITEM']['#']['HIDDEN']['0']['#'], false); $dbrec->locked = backup_todb($info['GRADE_ITEM']['#']['LOCKED']['0']['#'], false); $dbrec->locktime = backup_todb($info['GRADE_ITEM']['#']['LOCKTIME']['0']['#'], false); $dbrec->timecreated = backup_todb($info['GRADE_ITEM']['#']['TIMECREATED']['0']['#'], false); if (backup_todb($info['GRADE_ITEM']['#']['SCALEID']['0']['#'], false)) { $scale = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_ITEM']['#']['SCALEID']['0']['#'], false)); $dbrec->scaleid = $scale->new_id; } if (backup_todb($info['GRADE_ITEM']['#']['OUTCOMEID']['0']['#'])) { $oldoutcome = backup_todb($info['GRADE_ITEM']['#']['OUTCOMEID']['0']['#']); if (empty($outcomes[$oldoutcome])) { continue; // error! } if (empty($outcomes[$oldoutcome]->id)) { $outcomes[$oldoutcome]->insert('restore'); $outcomes[$oldoutcome]->use_in($restore->course_id); backup_putid($restore->backup_unique_code, "grade_outcomes", $oldoutcome, $outcomes[$oldoutcome]->id); } $dbrec->outcomeid = $outcomes[$oldoutcome]->id; } $grade_item = new grade_item($dbrec, false); $grade_item->insert('restore'); if ($restoreall) { // set original parent if restored $oldcat = $info['GRADE_ITEM']['#']['CATEGORYID']['0']['#']; if (!empty($cached_categories[$oldcat])) { $grade_item->set_parent($cached_categories[$oldcat]->id); } } $status = backup_putid($restore->backup_unique_code, "grade_items", $rec->old_id, $grade_item->id) && $status; } // no need to restore grades if user data is not selected or importing activities if ($importing or $grade_item->itemtype == 'mod' and !restore_userdata_selected($restore, $grade_item->itemmodule, $olditeminstance)) { // module instance not selected when restored using granular // skip this item continue; } /// now, restore grade_grades if (!empty($info['GRADE_ITEM']['#']['GRADE_GRADES']['0']['#']['GRADE'])) { //Iterate over items foreach ($info['GRADE_ITEM']['#']['GRADE_GRADES']['0']['#']['GRADE'] as $g_info) { $grade = new grade_grade(); $grade->itemid = $grade_item->id; $olduser = backup_todb($g_info['#']['USERID']['0']['#'], false); $user = backup_getid($restore->backup_unique_code, "user", $olduser); $grade->userid = $user->new_id; $grade->rawgrade = backup_todb($g_info['#']['RAWGRADE']['0']['#'], false); $grade->rawgrademax = backup_todb($g_info['#']['RAWGRADEMAX']['0']['#'], false); $grade->rawgrademin = backup_todb($g_info['#']['RAWGRADEMIN']['0']['#'], false); // need to find scaleid if (backup_todb($g_info['#']['RAWSCALEID']['0']['#'])) { $scale = backup_getid($restore->backup_unique_code, "scale", backup_todb($g_info['#']['RAWSCALEID']['0']['#'], false)); $grade->rawscaleid = $scale->new_id; } if (backup_todb($g_info['#']['USERMODIFIED']['0']['#'])) { if ($modifier = backup_getid($restore->backup_unique_code, "user", backup_todb($g_info['#']['USERMODIFIED']['0']['#'], false))) { $grade->usermodified = $modifier->new_id; } } $grade->finalgrade = backup_todb($g_info['#']['FINALGRADE']['0']['#'], false); $grade->hidden = backup_todb($g_info['#']['HIDDEN']['0']['#'], false); $grade->locked = backup_todb($g_info['#']['LOCKED']['0']['#'], false); $grade->locktime = backup_todb($g_info['#']['LOCKTIME']['0']['#'], false); $grade->exported = backup_todb($g_info['#']['EXPORTED']['0']['#'], false); $grade->overridden = backup_todb($g_info['#']['OVERRIDDEN']['0']['#'], false); $grade->excluded = backup_todb($g_info['#']['EXCLUDED']['0']['#'], false); $grade->feedback = backup_todb($g_info['#']['FEEDBACK']['0']['#'], false); $grade->feedbackformat = backup_todb($g_info['#']['FEEDBACKFORMAT']['0']['#'], false); $grade->information = backup_todb($g_info['#']['INFORMATION']['0']['#'], false); $grade->informationformat = backup_todb($g_info['#']['INFORMATIONFORMAT']['0']['#'], false); $grade->timecreated = backup_todb($g_info['#']['TIMECREATED']['0']['#'], false); $grade->timemodified = backup_todb($g_info['#']['TIMEMODIFIED']['0']['#'], false); $grade->insert('restore'); backup_putid($restore->backup_unique_code, "grade_grades", backup_todb($g_info['#']['ID']['0']['#']), $grade->id); $counter++; if ($counter % 20 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 400 == 0) { echo "<br />"; } } backup_flush(300); } } } } } } } /// add outcomes that are not used when doing full restore if ($status and $restoreall) { foreach ($outcomes as $oldoutcome => $grade_outcome) { if (empty($grade_outcome->id)) { $grade_outcome->insert('restore'); $grade_outcome->use_in($restore->course_id); backup_putid($restore->backup_unique_code, "grade_outcomes", $oldoutcome, $grade_outcome->id); } } } if ($status and !$importing and $restore_histories) { /// following code is very inefficient $gchcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'grade_categories_history'); $gghcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'grade_grades_history'); $gihcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'grade_items_history'); $gohcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'grade_outcomes_history'); // Number of records to get in every chunk $recordset_size = 2; // process histories if ($gchcount && $status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradecategoryhistory', 'grades') . '</li>'; } $counter = 0; while ($counter < $gchcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_categories_history' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_categories_history', $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug $oldobj = backup_getid($restore->backup_unique_code, "grade_categories", backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['OLDID']['0']['#'])); if (empty($oldobj->new_id)) { // if the old object is not being restored, can't restoring its history $counter++; continue; } $dbrec->oldid = $oldobj->new_id; $dbrec->action = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['ACTION']['0']['#']); $dbrec->source = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['SOURCE']['0']['#']); $dbrec->timemodified = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['TIMEMODIFIED']['0']['#']); // loggeduser might not be restored, e.g. admin if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['LOGGEDUSER']['0']['#']))) { $dbrec->loggeduser = $oldobj->new_id; } // this item might not have a parent at all, do not skip it if no parent is specified if (backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['PARENT']['0']['#'])) { $oldobj = backup_getid($restore->backup_unique_code, "grade_categories", backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['PARENT']['0']['#'])); if (empty($oldobj->new_id)) { // if the parent category not restored $counter++; continue; } } $dbrec->parent = $oldobj->new_id; $dbrec->depth = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['DEPTH']['0']['#']); // path needs to be rebuilt if ($path = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['PATH']['0']['#'])) { // to preserve the path and make it work, we need to replace the categories one by one // we first get the list of categories in current path if ($paths = explode("/", $path)) { $newpath = ''; foreach ($paths as $catid) { if ($catid) { // find the new corresponding path $oldpath = backup_getid($restore->backup_unique_code, "grade_categories", $catid); $newpath .= "/{$oldpath->new_id}"; } } $dbrec->path = $newpath; } } $dbrec->fullname = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['FULLNAME']['0']['#']); $dbrec->aggregation = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['AGGRETGATION']['0']['#']); $dbrec->keephigh = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['KEEPHIGH']['0']['#']); $dbrec->droplow = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['DROPLOW']['0']['#']); $dbrec->aggregateonlygraded = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['AGGREGATEONLYGRADED']['0']['#']); $dbrec->aggregateoutcomes = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['AGGREGATEOUTCOMES']['0']['#']); $dbrec->aggregatesubcats = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['AGGREGATESUBCATS']['0']['#']); $dbrec->courseid = $restore->course_id; insert_record('grade_categories_history', $dbrec); unset($dbrec); } //Increment counters $counter++; //Do some output if ($counter % 1 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 20 == 0) { echo "<br />"; } } backup_flush(300); } } } } } // process histories if ($gghcount && $status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradegradeshistory', 'grades') . '</li>'; } $counter = 0; while ($counter < $gghcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_grades_history' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_grades_history', $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug $oldobj = backup_getid($restore->backup_unique_code, "grade_grades", backup_todb($info['GRADE_GRADES_HISTORY']['#']['OLDID']['0']['#'])); if (empty($oldobj->new_id)) { // if the old object is not being restored, can't restoring its history $counter++; continue; } $dbrec->oldid = $oldobj->new_id; $dbrec->action = backup_todb($info['GRADE_GRADES_HISTORY']['#']['ACTION']['0']['#']); $dbrec->source = backup_todb($info['GRADE_GRADES_HISTORY']['#']['SOURCE']['0']['#']); $dbrec->timemodified = backup_todb($info['GRADE_GRADES_HISTORY']['#']['TIMEMODIFIED']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_GRADES_HISTORY']['#']['LOGGEDUSER']['0']['#']))) { $dbrec->loggeduser = $oldobj->new_id; } $oldobj = backup_getid($restore->backup_unique_code, "grade_items", backup_todb($info['GRADE_GRADES_HISTORY']['#']['ITEMID']['0']['#'])); $dbrec->itemid = $oldobj->new_id; if (empty($dbrec->itemid)) { $counter++; continue; // grade item not being restored } $oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_GRADES_HISTORY']['#']['USERID']['0']['#'])); $dbrec->userid = $oldobj->new_id; $dbrec->rawgrade = backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWGRADE']['0']['#']); $dbrec->rawgrademax = backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWGRADEMAX']['0']['#']); $dbrec->rawgrademin = backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWGRADEMIN']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_GRADES_HISTORY']['#']['USERMODIFIED']['0']['#']))) { $dbrec->usermodified = $oldobj->new_id; } if (backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWSCALEID']['0']['#'])) { $scale = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWSCALEID']['0']['#'])); $dbrec->rawscaleid = $scale->new_id; } $dbrec->finalgrade = backup_todb($info['GRADE_GRADES_HISTORY']['#']['FINALGRADE']['0']['#']); $dbrec->hidden = backup_todb($info['GRADE_GRADES_HISTORY']['#']['HIDDEN']['0']['#']); $dbrec->locked = backup_todb($info['GRADE_GRADES_HISTORY']['#']['LOCKED']['0']['#']); $dbrec->locktime = backup_todb($info['GRADE_GRADES_HISTORY']['#']['LOCKTIME']['0']['#']); $dbrec->exported = backup_todb($info['GRADE_GRADES_HISTORY']['#']['EXPORTED']['0']['#']); $dbrec->overridden = backup_todb($info['GRADE_GRADES_HISTORY']['#']['OVERRIDDEN']['0']['#']); $dbrec->excluded = backup_todb($info['GRADE_GRADES_HISTORY']['#']['EXCLUDED']['0']['#']); $dbrec->feedback = backup_todb($info['GRADE_TEXT_HISTORY']['#']['FEEDBACK']['0']['#']); $dbrec->feedbackformat = backup_todb($info['GRADE_TEXT_HISTORY']['#']['FEEDBACKFORMAT']['0']['#']); $dbrec->information = backup_todb($info['GRADE_TEXT_HISTORY']['#']['INFORMATION']['0']['#']); $dbrec->informationformat = backup_todb($info['GRADE_TEXT_HISTORY']['#']['INFORMATIONFORMAT']['0']['#']); insert_record('grade_grades_history', $dbrec); unset($dbrec); } //Increment counters $counter++; //Do some output if ($counter % 1 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 20 == 0) { echo "<br />"; } } backup_flush(300); } } } } } // process histories if ($gihcount && $status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeitemshistory', 'grades') . '</li>'; } $counter = 0; while ($counter < $gihcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_items_history' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_items_history', $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug $oldobj = backup_getid($restore->backup_unique_code, "grade_items", backup_todb($info['GRADE_ITEM_HISTORY']['#']['OLDID']['0']['#'])); if (empty($oldobj->new_id)) { // if the old object is not being restored, can't restoring its history $counter++; continue; } $dbrec->oldid = $oldobj->new_id; $dbrec->action = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ACTION']['0']['#']); $dbrec->source = backup_todb($info['GRADE_ITEM_HISTORY']['#']['SOURCE']['0']['#']); $dbrec->timemodified = backup_todb($info['GRADE_ITEM_HISTORY']['#']['TIMEMODIFIED']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_ITEM_HISTORY']['#']['LOGGEDUSER']['0']['#']))) { $dbrec->loggeduser = $oldobj->new_id; } $dbrec->courseid = $restore->course_id; $oldobj = backup_getid($restore->backup_unique_code, 'grade_categories', backup_todb($info['GRADE_ITEM_HISTORY']['#']['CATEGORYID']['0']['#'])); $oldobj->categoryid = $category->new_id; if (empty($oldobj->categoryid)) { $counter++; continue; // category not restored } $dbrec->itemname = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMNAME']['0']['#']); $dbrec->itemtype = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMTYPE']['0']['#']); $dbrec->itemmodule = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMMODULE']['0']['#']); // code from grade_items restore $iteminstance = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMINSTANCE']['0']['#']); // do not restore if this grade_item is a mod, and if ($dbrec->itemtype == 'mod') { if (!restore_userdata_selected($restore, $dbrec->itemmodule, $iteminstance)) { // module instance not selected when restored using granular // skip this item $counter++; continue; } // iteminstance should point to new mod $mod = backup_getid($restore->backup_unique_code, $dbrec->itemmodule, $iteminstance); $dbrec->iteminstance = $mod->new_id; } else { if ($dbrec->itemtype == 'category') { // the item instance should point to the new grade category // only proceed if we are restoring all grade items if ($restoreall) { $category = backup_getid($restore->backup_unique_code, 'grade_categories', $iteminstance); $dbrec->iteminstance = $category->new_id; } else { // otherwise we can safely ignore this grade item and subsequent // grade_raws, grade_finals etc continue; } } elseif ($dbrec->itemtype == 'course') { // We don't restore course type to avoid duplicate course items if ($restoreall) { // TODO any special code needed here to restore course item without duplicating it? // find the course category with depth 1, and course id = current course id // this would have been already restored $cat = get_record('grade_categories', 'depth', 1, 'courseid', $restore->course_id); $dbrec->iteminstance = $cat->id; } else { $counter++; continue; } } } $dbrec->itemnumber = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMNUMBER']['0']['#']); $dbrec->iteminfo = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMINFO']['0']['#']); $dbrec->idnumber = backup_todb($info['GRADE_ITEM_HISTORY']['#']['IDNUMBER']['0']['#']); $dbrec->calculation = backup_todb($info['GRADE_ITEM_HISTORY']['#']['CALCULATION']['0']['#']); $dbrec->gradetype = backup_todb($info['GRADE_ITEM_HISTORY']['#']['GRADETYPE']['0']['#']); $dbrec->grademax = backup_todb($info['GRADE_ITEM_HISTORY']['#']['GRADEMAX']['0']['#']); $dbrec->grademin = backup_todb($info['GRADE_ITEM_HISTORY']['#']['GRADEMIN']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_ITEM_HISTORY']['#']['SCALEID']['0']['#']))) { // scaleid is optional $dbrec->scaleid = $oldobj->new_id; } if ($oldobj = backup_getid($restore->backup_unique_code, "grade_outcomes", backup_todb($info['GRADE_ITEM_HISTORY']['#']['OUTCOMEID']['0']['#']))) { // outcome is optional $dbrec->outcomeid = $oldobj->new_id; } $dbrec->gradepass = backup_todb($info['GRADE_ITEM_HISTORY']['#']['GRADEPASS']['0']['#']); $dbrec->multfactor = backup_todb($info['GRADE_ITEM_HISTORY']['#']['MULTFACTOR']['0']['#']); $dbrec->plusfactor = backup_todb($info['GRADE_ITEM_HISTORY']['#']['PLUSFACTOR']['0']['#']); $dbrec->aggregationcoef = backup_todb($info['GRADE_ITEM_HISTORY']['#']['AGGREGATIONCOEF']['0']['#']); $dbrec->sortorder = backup_todb($info['GRADE_ITEM_HISTORY']['#']['SORTORDER']['0']['#']); $dbrec->display = backup_todb($info['GRADE_ITEM_HISTORY']['#']['DISPLAY']['0']['#']); $dbrec->decimals = backup_todb($info['GRADE_ITEM_HISTORY']['#']['DECIMALS']['0']['#']); $dbrec->hidden = backup_todb($info['GRADE_ITEM_HISTORY']['#']['HIDDEN']['0']['#']); $dbrec->locked = backup_todb($info['GRADE_ITEM_HISTORY']['#']['LOCKED']['0']['#']); $dbrec->locktime = backup_todb($info['GRADE_ITEM_HISTORY']['#']['LOCKTIME']['0']['#']); $dbrec->needsupdate = backup_todb($info['GRADE_ITEM_HISTORY']['#']['NEEDSUPDATE']['0']['#']); insert_record('grade_items_history', $dbrec); unset($dbrec); } //Increment counters $counter++; //Do some output if ($counter % 1 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 20 == 0) { echo "<br />"; } } backup_flush(300); } } } } } // process histories if ($gohcount && $status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeoutcomeshistory', 'grades') . '</li>'; } $counter = 0; while ($counter < $gohcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_outcomes_history' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_outcomes_history', $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug $oldobj = backup_getid($restore->backup_unique_code, "grade_outcomes", backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['OLDID']['0']['#'])); if (empty($oldobj->new_id)) { // if the old object is not being restored, can't restoring its history $counter++; continue; } $dbrec->oldid = $oldobj->new_id; $dbrec->action = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['ACTION']['0']['#']); $dbrec->source = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['SOURCE']['0']['#']); $dbrec->timemodified = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['TIMEMODIFIED']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['LOGGEDUSER']['0']['#']))) { $dbrec->loggeduser = $oldobj->new_id; } $dbrec->courseid = $restore->course_id; $dbrec->shortname = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['SHORTNAME']['0']['#']); $dbrec->fullname = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['FULLNAME']['0']['#']); $oldobj = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['SCALEID']['0']['#'])); $dbrec->scaleid = $oldobj->new_id; $dbrec->description = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['DESCRIPTION']['0']['#']); insert_record('grade_outcomes_history', $dbrec); unset($dbrec); } //Increment counters $counter++; //Do some output if ($counter % 1 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 20 == 0) { echo "<br />"; } } backup_flush(300); } } } } } } if (!defined('RESTORE_SILENTLY')) { //End ul echo '</ul>'; } return $status; }
private function fill_table_recursive(&$element) { global $DB, $CFG; $type = $element['type']; $depth = $element['depth']; $grade_object = $element['object']; $eid = $grade_object->id; $element['userid'] = $this->user->id; $fullname = $this->gtree->get_element_header($element, true, true, true); $data = array(); $hidden = ''; $excluded = ''; $class = ''; $classfeedback = ''; // If this is a hidden grade category, hide it completely from the user if ($type == 'category' && $grade_object->is_hidden() && !$this->canviewhidden && ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN || $this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_object->is_hiddenuntil())) { return false; } if ($type == 'category') { $this->evenodd[$depth] = ($this->evenodd[$depth] + 1) % 2; } $alter = $this->evenodd[$depth] == 0 ? 'even' : 'odd'; /// Process those items that have scores associated if ($type == 'item' or $type == 'categoryitem' or $type == 'courseitem') { $header_row = "row_{$eid}_{$this->user->id}"; $header_cat = "cat_{$grade_object->categoryid}_{$this->user->id}"; if (!($grade_grade = grade_grade::fetch(array('itemid' => $grade_object->id, 'userid' => $this->user->id)))) { $grade_grade = new grade_grade(); $grade_grade->userid = $this->user->id; $grade_grade->itemid = $grade_object->id; } $grade_grade->load_grade_item(); /// Hidden Items if ($grade_grade->grade_item->is_hidden()) { $hidden = ' dimmed_text'; } $hide = false; // If this is a hidden grade item, hide it completely from the user. if ($grade_grade->is_hidden() && !$this->canviewhidden && ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN || $this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_grade->is_hiddenuntil())) { $hide = true; } else { if (!empty($grade_object->itemmodule) && !empty($grade_object->iteminstance)) { // The grade object can be marked visible but still be hidden if // the student cannot see the activity due to conditional access // and it's set to be hidden entirely. $instances = $this->modinfo->get_instances_of($grade_object->itemmodule); if (!empty($instances[$grade_object->iteminstance])) { $cm = $instances[$grade_object->iteminstance]; if (!$cm->uservisible) { // If there is 'availableinfo' text then it is only greyed // out and not entirely hidden. if (!$cm->availableinfo) { $hide = true; } } } } } if (!$hide) { /// Excluded Item if ($grade_grade->is_excluded()) { $fullname .= ' [' . get_string('excluded', 'grades') . ']'; $excluded = ' excluded'; } /// Other class information $class = "{$hidden} {$excluded}"; if ($this->switch) { // alter style based on whether aggregation is first or last $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " " . $alter . "d{$depth} baggt b2b" : " item b1b"; } else { $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " " . $alter . "d{$depth} baggb" : " item b1b"; } if ($type == 'categoryitem' or $type == 'courseitem') { $header_cat = "cat_{$grade_object->iteminstance}_{$this->user->id}"; } /// Name $data['itemname']['content'] = $fullname; $data['itemname']['class'] = $class; $data['itemname']['colspan'] = $this->maxdepth - $depth; $data['itemname']['celltype'] = 'th'; $data['itemname']['id'] = $header_row; /// Actual Grade $gradeval = $grade_grade->finalgrade; if (!$this->canviewhidden) { /// Virtual Grade (may be calculated excluding hidden items etc). $adjustedgrade = $this->blank_hidden_total_and_adjust_bounds($this->courseid, $grade_grade->grade_item, $gradeval); $gradeval = $adjustedgrade['grade']; // We temporarily adjust the view of this grade item - because the min and // max are affected by the hidden values in the aggregation. $grade_grade->grade_item->grademax = $adjustedgrade['grademax']; $grade_grade->grade_item->grademin = $adjustedgrade['grademin']; } if ($this->showfeedback) { // Copy $class before appending itemcenter as feedback should not be centered $classfeedback = $class; } $class .= " itemcenter "; if ($this->showweight) { $data['weight']['class'] = $class; $data['weight']['content'] = '-'; $data['weight']['headers'] = "{$header_cat} {$header_row} weight"; // has a weight assigned, might be extra credit if ($grade_object->aggregationcoef > 0 && $type != 'courseitem') { $data['weight']['content'] = number_format($grade_object->aggregationcoef, 2); } } if ($this->showgrade) { if ($grade_grade->grade_item->needsupdate) { $data['grade']['class'] = $class . ' gradingerror'; $data['grade']['content'] = get_string('error'); } else { if (!empty($CFG->grade_hiddenasdate) and $grade_grade->get_datesubmitted() and !$this->canviewhidden and $grade_grade->is_hidden() and !$grade_grade->grade_item->is_category_item() and !$grade_grade->grade_item->is_course_item()) { // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records $class .= ' datesubmitted'; $data['grade']['class'] = $class; $data['grade']['content'] = get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort'))); } else { if ($grade_grade->is_hidden()) { $data['grade']['class'] = $class . ' dimmed_text'; $data['grade']['content'] = '-'; if ($this->canviewhidden) { $data['grade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true); } } else { $data['grade']['class'] = $class; $data['grade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true); } } } $data['grade']['headers'] = "{$header_cat} {$header_row} grade"; } // Range if ($this->showrange) { $data['range']['class'] = $class; $data['range']['content'] = $grade_grade->grade_item->get_formatted_range(GRADE_DISPLAY_TYPE_REAL, $this->rangedecimals); $data['range']['headers'] = "{$header_cat} {$header_row} range"; } // Percentage if ($this->showpercentage) { if ($grade_grade->grade_item->needsupdate) { $data['percentage']['class'] = $class . ' gradingerror'; $data['percentage']['content'] = get_string('error'); } else { if ($grade_grade->is_hidden()) { $data['percentage']['class'] = $class . ' dimmed_text'; $data['percentage']['content'] = '-'; if ($this->canviewhidden) { $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE); } } else { $data['percentage']['class'] = $class; $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE); } } $data['percentage']['headers'] = "{$header_cat} {$header_row} percentage"; } // Lettergrade if ($this->showlettergrade) { if ($grade_grade->grade_item->needsupdate) { $data['lettergrade']['class'] = $class . ' gradingerror'; $data['lettergrade']['content'] = get_string('error'); } else { if ($grade_grade->is_hidden()) { $data['lettergrade']['class'] = $class . ' dimmed_text'; if (!$this->canviewhidden) { $data['lettergrade']['content'] = '-'; } else { $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER); } } else { $data['lettergrade']['class'] = $class; $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER); } } $data['lettergrade']['headers'] = "{$header_cat} {$header_row} lettergrade"; } // Rank if ($this->showrank) { if ($grade_grade->grade_item->needsupdate) { $data['rank']['class'] = $class . ' gradingerror'; $data['rank']['content'] = get_string('error'); } elseif ($grade_grade->is_hidden()) { $data['rank']['class'] = $class . ' dimmed_text'; $data['rank']['content'] = '-'; } else { if (is_null($gradeval)) { // no grade, no rank $data['rank']['class'] = $class; $data['rank']['content'] = '-'; } else { /// find the number of users with a higher grade $sql = "SELECT COUNT(DISTINCT(userid))\n FROM {grade_grades}\n WHERE finalgrade > ?\n AND itemid = ?\n AND hidden = 0"; $rank = $DB->count_records_sql($sql, array($grade_grade->finalgrade, $grade_grade->grade_item->id)) + 1; $data['rank']['class'] = $class; $data['rank']['content'] = "{$rank}/" . $this->get_numusers(false); // total course users } } $data['rank']['headers'] = "{$header_cat} {$header_row} rank"; } // Average if ($this->showaverage) { $data['average']['class'] = $class; if (!empty($this->gtree->items[$eid]->avg)) { $data['average']['content'] = $this->gtree->items[$eid]->avg; } else { $data['average']['content'] = '-'; } $data['average']['headers'] = "{$header_cat} {$header_row} average"; } // Feedback if ($this->showfeedback) { if ($grade_grade->overridden > 0 and ($type == 'categoryitem' or $type == 'courseitem')) { $data['feedback']['class'] = $classfeedback . ' feedbacktext'; $data['feedback']['content'] = get_string('overridden', 'grades') . ': ' . format_text($grade_grade->feedback, $grade_grade->feedbackformat); } else { if (empty($grade_grade->feedback) or !$this->canviewhidden and $grade_grade->is_hidden()) { $data['feedback']['class'] = $classfeedback . ' feedbacktext'; $data['feedback']['content'] = ' '; } else { $data['feedback']['class'] = $classfeedback . ' feedbacktext'; $data['feedback']['content'] = format_text($grade_grade->feedback, $grade_grade->feedbackformat); } } $data['feedback']['headers'] = "{$header_cat} {$header_row} feedback"; } } } /// Category if ($type == 'category') { $data['leader']['class'] = $class . ' ' . $alter . "d{$depth} b1t b2b b1l"; $data['leader']['rowspan'] = $element['rowspan']; if ($this->switch) { // alter style based on whether aggregation is first or last $data['itemname']['class'] = $class . ' ' . $alter . "d{$depth} b1b b1t"; } else { $data['itemname']['class'] = $class . ' ' . $alter . "d{$depth} b2t"; } $data['itemname']['colspan'] = $this->maxdepth - $depth + count($this->tablecolumns) - 1; $data['itemname']['content'] = $fullname; $data['itemname']['celltype'] = 'th'; $data['itemname']['id'] = "cat_{$grade_object->id}_{$this->user->id}"; } /// Add this row to the overall system $this->tabledata[] = $data; /// Recursively iterate through all child elements if (isset($element['children'])) { foreach ($element['children'] as $key => $child) { $this->fill_table_recursive($element['children'][$key]); } } }
/** * Grading cron job. Performs background clean up on the gradebook */ function grade_cron() { global $CFG, $DB; $now = time(); $sql = "SELECT i.*\n FROM {grade_items} i\n WHERE i.locked = 0 AND i.locktime > 0 AND i.locktime < ? AND EXISTS (\n SELECT 'x' FROM {grade_items} c WHERE c.itemtype='course' AND c.needsupdate=0 AND c.courseid=i.courseid)"; // go through all courses that have proper final grades and lock them if needed $rs = $DB->get_recordset_sql($sql, array($now)); foreach ($rs as $item) { $grade_item = new grade_item($item, false); $grade_item->locked = $now; $grade_item->update('locktime'); } $rs->close(); $grade_inst = new grade_grade(); $fields = 'g.' . implode(',g.', $grade_inst->required_fields); $sql = "SELECT {$fields}\n FROM {grade_grades} g, {grade_items} i\n WHERE g.locked = 0 AND g.locktime > 0 AND g.locktime < ? AND g.itemid=i.id AND EXISTS (\n SELECT 'x' FROM {grade_items} c WHERE c.itemtype='course' AND c.needsupdate=0 AND c.courseid=i.courseid)"; // go through all courses that have proper final grades and lock them if needed $rs = $DB->get_recordset_sql($sql, array($now)); foreach ($rs as $grade) { $grade_grade = new grade_grade($grade, false); $grade_grade->locked = $now; $grade_grade->update('locktime'); } $rs->close(); //TODO: do not run this cleanup every cron invocation // cleanup history tables if (!empty($CFG->gradehistorylifetime)) { // value in days $histlifetime = $now - $CFG->gradehistorylifetime * 3600 * 24; $tables = array('grade_outcomes_history', 'grade_categories_history', 'grade_items_history', 'grade_grades_history', 'scale_history'); foreach ($tables as $table) { if ($DB->delete_records_select($table, "timemodified < ?", array($histlifetime))) { mtrace(" Deleted old grade history records from '{$table}'"); } } } }
function import_xml_grades($text, $course, &$error) { global $USER; $importcode = get_new_importcode(); $status = true; $content = xmlize($text); if (!empty($content['results']['#']['result'])) { $results = $content['results']['#']['result']; foreach ($results as $i => $result) { $gradeidnumber = $result['#']['assignment'][0]['#']; if (!($grade_items = grade_item::fetch_all(array('idnumber' => $gradeidnumber, 'courseid' => $course->id)))) { // gradeitem does not exist // no data in temp table so far, abort $status = false; $error = get_string('errincorrectgradeidnumber', 'gradeimport_xml', $gradeidnumber); break; } else { if (count($grade_items) != 1) { $status = false; $error = get_string('errduplicategradeidnumber', 'gradeimport_xml', $gradeidnumber); break; } else { $grade_item = reset($grade_items); } } // grade item locked, abort if ($grade_item->is_locked()) { $status = false; $error = get_string('gradeitemlocked', 'grades'); break; } // check if user exist and convert idnumber to user id $useridnumber = $result['#']['student'][0]['#']; if (!($user = get_record('user', 'idnumber', addslashes($useridnumber)))) { // no user found, abort $status = false; $error = get_string('errincorrectuseridnumber', 'gradeimport_xml', $useridnumber); break; } // check if grade_grade is locked and if so, abort if ($grade_grade = new grade_grade(array('itemid' => $grade_item->id, 'userid' => $user->id))) { $grade_grade->grade_item =& $grade_item; if ($grade_grade->is_locked()) { // individual grade locked, abort $status = false; $error = get_string('gradegradeslocked', 'grades'); break; } } $newgrade = new object(); $newgrade->itemid = $grade_item->id; $newgrade->userid = $user->id; $newgrade->importcode = $importcode; $newgrade->importer = $USER->id; // check grade value exists and is a numeric grade if (isset($result['#']['score'][0]['#'])) { if (is_numeric($result['#']['score'][0]['#'])) { $newgrade->finalgrade = $result['#']['score'][0]['#']; } else { $status = false; $error = get_string('badgrade', 'grades'); break; } } else { $newgrade->finalgrade = NULL; } // check grade feedback exists if (isset($result['#']['feedback'][0]['#'])) { $newgrade->feedback = $result['#']['feedback'][0]['#']; } else { $newgrade->feedback = NULL; } // insert this grade into a temp table if (!insert_record('grade_import_values', addslashes_recursive($newgrade))) { $status = false; // could not insert into temp table $error = get_string('importfailed', 'grades'); break; } } } else { // no results section found in xml, // assuming bad format, abort import $status = false; $error = get_string('errbadxmlformat', 'gradeimport_xml'); } if ($status) { return $importcode; } else { import_cleanup($importcode); return false; } }
protected function sub_test_update_final_grade() { // MDL-31713 Check that min and max are set on the grade_grade instance // if the grade is overridden before the activity has supplied a grade. $min = 2; $max = 8; // Create a brand new grade item. $grade_item = new grade_item(); $this->assertTrue(method_exists($grade_item, 'insert')); $grade_item->courseid = $this->courseid; $grade_item->categoryid = $this->grade_categories[1]->id; $grade_item->itemname = 'brand new unit test grade item'; $grade_item->itemtype = 'mod'; $grade_item->itemmodule = 'quiz'; $grade_item->iteminfo = 'Grade item used for unit testing'; $grade_item->grademin = $min; $grade_item->grademax = $max; $grade_item->insert(); // Override the student grade. $grade_item->update_final_grade($this->user[1]->id, 7, 'gradebook', '', FORMAT_MOODLE); // Check the student's grade has the correct min and max grade. $grade_grade = grade_grade::fetch(array('userid' => $this->user[1]->id, 'itemid' => $grade_item->id)); $this->assertEquals($min, $grade_grade->rawgrademin); $this->assertEquals($max, $grade_grade->rawgrademax); }