/** * Initialise the iterator * @return boolean success */ function init() { global $CFG; $this->close(); grade_regrade_final_grades($this->course->id); $course_item = grade_item::fetch_course_item($this->course->id); if ($course_item->needsupdate) { // can not calculate all final grades - sorry return false; } if (strpos($CFG->gradebookroles, ',') !== false) { $gradebookroles = " = {$CFG->gradebookroles}"; } else { $gradebookroles = " IN ({$CFG->gradebookroles})"; } $relatedcontexts = get_related_contexts_string(get_context_instance(CONTEXT_COURSE, $this->course->id)); if ($this->groupid) { $groupsql = "INNER JOIN {$CFG->prefix}groups_members gm ON gm.userid = u.id"; $groupwheresql = "AND gm.groupid = {$this->groupid}"; } else { $groupsql = ""; $groupwheresql = ""; } $users_sql = "SELECT u.*\n FROM {$CFG->prefix}user u\n INNER JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid\n {$groupsql}\n WHERE ra.roleid {$gradebookroles}\n AND ra.contextid {$relatedcontexts}\n {$groupwheresql}\n ORDER BY u.id ASC"; $this->users_rs = get_recordset_sql($users_sql); if (!empty($this->grade_items)) { $itemids = array_keys($this->grade_items); $itemids = implode(',', $itemids); $grades_sql = "SELECT g.*\n FROM {$CFG->prefix}grade_grades g\n INNER JOIN {$CFG->prefix}user u ON g.userid = u.id\n INNER JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid\n {$groupsql}\n WHERE ra.roleid {$gradebookroles}\n AND ra.contextid {$relatedcontexts}\n AND g.itemid IN ({$itemids})\n {$groupwheresql}\n ORDER BY g.userid ASC, g.itemid ASC"; $this->grades_rs = get_recordset_sql($grades_sql); } return true; }
/** * Initialise the iterator * @return boolean success */ public function init() { global $CFG, $DB; $this->close(); grade_regrade_final_grades($this->course->id); $course_item = grade_item::fetch_course_item($this->course->id); if ($course_item->needsupdate) { // can not calculate all final grades - sorry return false; } $coursecontext = get_context_instance(CONTEXT_COURSE, $this->course->id); $relatedcontexts = get_related_contexts_string($coursecontext); list($gradebookroles_sql, $params) = $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr'); //limit to users with an active enrolment list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext); $params = array_merge($params, $enrolledparams); if ($this->groupid) { $groupsql = "INNER JOIN {groups_members} gm ON gm.userid = u.id"; $groupwheresql = "AND gm.groupid = :groupid"; // $params contents: gradebookroles $params['groupid'] = $this->groupid; } else { $groupsql = ""; $groupwheresql = ""; } if (empty($this->sortfield1)) { // we must do some sorting even if not specified $ofields = ", u.id AS usrt"; $order = "usrt ASC"; } else { $ofields = ", u.{$this->sortfield1} AS usrt1"; $order = "usrt1 {$this->sortorder1}"; if (!empty($this->sortfield2)) { $ofields .= ", u.{$this->sortfield2} AS usrt2"; $order .= ", usrt2 {$this->sortorder2}"; } if ($this->sortfield1 != 'id' and $this->sortfield2 != 'id') { // user order MUST be the same in both queries, // must include the only unique user->id if not already present $ofields .= ", u.id AS usrt"; $order .= ", usrt ASC"; } } // $params contents: gradebookroles and groupid (for $groupwheresql) $users_sql = "SELECT u.* {$ofields}\n FROM {user} u\n JOIN ({$enrolledsql}) je ON je.id = u.id\n {$groupsql}\n JOIN (\n SELECT DISTINCT ra.userid\n FROM {role_assignments} ra\n WHERE ra.roleid {$gradebookroles_sql}\n AND ra.contextid {$relatedcontexts}\n ) rainner ON rainner.userid = u.id\n WHERE u.deleted = 0\n {$groupwheresql}\n ORDER BY {$order}"; $this->users_rs = $DB->get_recordset_sql($users_sql, $params); if (!empty($this->grade_items)) { $itemids = array_keys($this->grade_items); list($itemidsql, $grades_params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED, 'items'); $params = array_merge($params, $grades_params); // $params contents: gradebookroles, enrolledparams, groupid (for $groupwheresql) and itemids $grades_sql = "SELECT g.* {$ofields}\n FROM {grade_grades} g\n JOIN {user} u ON g.userid = u.id\n JOIN ({$enrolledsql}) je ON je.id = u.id\n {$groupsql}\n JOIN (\n SELECT DISTINCT ra.userid\n FROM {role_assignments} ra\n WHERE ra.roleid {$gradebookroles_sql}\n AND ra.contextid {$relatedcontexts}\n ) rainner ON rainner.userid = u.id\n WHERE u.deleted = 0\n AND g.itemid {$itemidsql}\n {$groupwheresql}\n ORDER BY {$order}, g.itemid ASC"; $this->grades_rs = $DB->get_recordset_sql($grades_sql, $params); } else { $this->grades_rs = false; } return true; }
/** * Initialise the iterator * @return boolean success */ function init() { global $CFG; $this->close(); grade_regrade_final_grades($this->course->id); $course_item = grade_item::fetch_course_item($this->course->id); if ($course_item->needsupdate) { // can not calculate all final grades - sorry return false; } if (strpos($CFG->gradebookroles, ',') === false) { $gradebookroles = " = {$CFG->gradebookroles}"; } else { $gradebookroles = " IN ({$CFG->gradebookroles})"; } $relatedcontexts = get_related_contexts_string(get_context_instance(CONTEXT_COURSE, $this->course->id)); if ($this->groupid) { $groupsql = "INNER JOIN {$CFG->prefix}groups_members gm ON gm.userid = u.id"; $groupwheresql = "AND gm.groupid = {$this->groupid}"; } else { $groupsql = ""; $groupwheresql = ""; } if (empty($this->sortfield1)) { // we must do some sorting even if not specified $ofields = ", u.id AS usrt"; $order = "usrt ASC"; } else { $ofields = ", u.{$this->sortfield1} AS usrt1"; $order = "usrt1 {$this->sortorder1}"; if (!empty($this->sortfield2)) { $ofields .= ", u.{$this->sortfield2} AS usrt2"; $order .= ", usrt2 {$this->sortorder2}"; } if ($this->sortfield1 != 'id' and $this->sortfield2 != 'id') { // user order MUST be the same in both queries, must include the only unique user->id if not already present $ofields .= ", u.id AS usrt"; $order .= ", usrt ASC"; } } $users_sql = "SELECT u.* {$ofields}\n FROM {$CFG->prefix}user u\n INNER JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid\n {$groupsql}\n WHERE ra.roleid {$gradebookroles}\n AND ra.contextid {$relatedcontexts}\n {$groupwheresql}\n ORDER BY {$order}"; $this->users_rs = get_recordset_sql($users_sql); if (!empty($this->grade_items)) { $itemids = array_keys($this->grade_items); $itemids = implode(',', $itemids); $grades_sql = "SELECT g.* {$ofields}\n FROM {$CFG->prefix}grade_grades g\n INNER JOIN {$CFG->prefix}user u ON g.userid = u.id\n INNER JOIN {$CFG->prefix}role_assignments ra ON u.id = ra.userid\n {$groupsql}\n WHERE ra.roleid {$gradebookroles}\n AND ra.contextid {$relatedcontexts}\n AND g.itemid IN ({$itemids})\n {$groupwheresql}\n ORDER BY {$order}, g.itemid ASC"; $this->grades_rs = get_recordset_sql($grades_sql); } else { $this->grades_rs = false; } return true; }
/** * Test load_users method. */ public function test_load_users() { global $DB; $this->setAdminUser(); $this->resetAfterTest(true); $roleteacher = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST); // Create a course, users and groups. $course = $this->getDataGenerator()->create_course(); $coursecontext = context_course::instance($course->id); $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $teacher = $this->getDataGenerator()->create_user(); $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $roleteacher->id); $this->getDataGenerator()->enrol_user($user1->id, $course->id); $this->getDataGenerator()->enrol_user($user2->id, $course->id); $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $teacher->id)); $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user1->id)); $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user2->id)); // Perform a regrade before creating the report. grade_regrade_final_grades($course->id); $screentest = new gradereport_singleview_screen_testable($course->id, 0, $group->id); $groupusers = $screentest->test_load_users(); $this->assertCount(2, $groupusers); // Now, let's suspend the enrolment of a user. Should return only one user. $this->getDataGenerator()->enrol_user($user2->id, $course->id, $roleteacher->id, 'manual', 0, 0, ENROL_USER_SUSPENDED); $users = $screentest->test_load_users(); $this->assertCount(1, $users); // Change the viewsuspendedusers capabilities and set the user preference to display suspended users. assign_capability('moodle/course:viewsuspendedusers', CAP_ALLOW, $roleteacher->id, $coursecontext, true); set_user_preference('grade_report_showonlyactiveenrol', false, $teacher); accesslib_clear_all_caches_for_unit_testing(); $this->setUser($teacher); $screentest = new gradereport_singleview_screen_testable($course->id, 0, $group->id); $users = $screentest->test_load_users(); $this->assertCount(2, $users); // Change the capability again, now the user can't see the suspended enrolments. assign_capability('moodle/course:viewsuspendedusers', CAP_PROHIBIT, $roleteacher->id, $coursecontext, true); set_user_preference('grade_report_showonlyactiveenrol', false, $teacher); accesslib_clear_all_caches_for_unit_testing(); $users = $screentest->test_load_users(); $this->assertCount(1, $users); // Now, activate the user enrolment again. We shall get 2 users now. $this->getDataGenerator()->enrol_user($user2->id, $course->id, $roleteacher->id, 'manual', 0, 0, ENROL_USER_ACTIVE); $users = $screentest->test_load_users(); $this->assertCount(2, $users); }
protected function sub_test_grade_category_set_locked() { $category = new grade_category($this->grade_categories[0]); $this->assertTrue(method_exists($category, 'set_locked')); //will return false as cannot lock a grade that needs updating $this->assertFalse($category->set_locked(1)); grade_regrade_final_grades($this->courseid); //get the category from the db again $category = new grade_category($this->grade_categories[0]); $this->assertTrue($category->set_locked(1)); }
/** * This function will empty a course of user data. * It will retain the activities and the structure of the course. * @param object $data an object containing all the settings including courseid (without magic quotes) * @return array status array of array component, item, error */ function reset_course_userdata($data) { global $CFG, $USER; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/group/lib.php'; $data->courseid = $data->id; $context = get_context_instance(CONTEXT_COURSE, $data->courseid); // calculate the time shift of dates if (!empty($data->reset_start_date)) { // time part of course startdate should be zero $data->timeshift = $data->reset_start_date - usergetmidnight($data->reset_start_date_old); } else { $data->timeshift = 0; } // result array: component, item, error $status = array(); // start the resetting $componentstr = get_string('general'); // move the course start time if (!empty($data->reset_start_date) and $data->timeshift) { // change course start data set_field('course', 'startdate', $data->reset_start_date, 'id', $data->courseid); // update all course and group events - do not move activity events $updatesql = "UPDATE {$CFG->prefix}event\n SET timestart = timestart + ({$data->timeshift})\n WHERE courseid={$data->courseid} AND instance=0"; execute_sql($updatesql, false); $status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false); } if (!empty($data->reset_logs)) { delete_records('log', 'course', $data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deletelogs'), 'error' => false); } if (!empty($data->reset_events)) { delete_records('event', 'courseid', $data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deleteevents', 'calendar'), 'error' => false); } if (!empty($data->reset_notes)) { require_once $CFG->dirroot . '/notes/lib.php'; note_delete_all($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deletenotes', 'notes'), 'error' => false); } $componentstr = get_string('roles'); if (!empty($data->reset_roles_overrides)) { $children = get_child_contexts($context); foreach ($children as $child) { delete_records('role_capabilities', 'contextid', $child->id); } delete_records('role_capabilities', 'contextid', $context->id); //force refresh for logged in users mark_context_dirty($context->path); $status[] = array('component' => $componentstr, 'item' => get_string('deletecourseoverrides', 'role'), 'error' => false); } if (!empty($data->reset_roles_local)) { $children = get_child_contexts($context); foreach ($children as $child) { role_unassign(0, 0, 0, $child->id); } //force refresh for logged in users mark_context_dirty($context->path); $status[] = array('component' => $componentstr, 'item' => get_string('deletelocalroles', 'role'), 'error' => false); } // First unenrol users - this cleans some of related user data too, such as forum subscriptions, tracking, etc. $data->unenrolled = array(); if (!empty($data->reset_roles)) { foreach ($data->reset_roles as $roleid) { if ($users = get_role_users($roleid, $context, false, 'u.id', 'u.id ASC')) { foreach ($users as $user) { role_unassign($roleid, $user->id, 0, $context->id); if (!has_capability('moodle/course:view', $context, $user->id)) { $data->unenrolled[$user->id] = $user->id; } } } } } if (!empty($data->unenrolled)) { $status[] = array('component' => $componentstr, 'item' => get_string('unenrol') . ' (' . count($data->unenrolled) . ')', 'error' => false); } $componentstr = get_string('groups'); // remove all group members if (!empty($data->reset_groups_members)) { groups_delete_group_members($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removegroupsmembers', 'group'), 'error' => false); } // remove all groups if (!empty($data->reset_groups_remove)) { groups_delete_groups($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroups', 'group'), 'error' => false); } // remove all grouping members if (!empty($data->reset_groupings_members)) { groups_delete_groupings_groups($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('removegroupingsmembers', 'group'), 'error' => false); } // remove all groupings if (!empty($data->reset_groupings_remove)) { groups_delete_groupings($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroupings', 'group'), 'error' => false); } // Look in every instance of every module for data to delete $unsupported_mods = array(); if ($allmods = get_records('modules')) { foreach ($allmods as $mod) { $modname = $mod->name; if (!count_records($modname, 'course', $data->courseid)) { continue; // skip mods with no instances } $modfile = $CFG->dirroot . '/mod/' . $modname . '/lib.php'; $moddeleteuserdata = $modname . '_reset_userdata'; // Function to delete user data if (file_exists($modfile)) { include_once $modfile; if (function_exists($moddeleteuserdata)) { $modstatus = $moddeleteuserdata($data); if (is_array($modstatus)) { $status = array_merge($status, $modstatus); } else { debugging('Module ' . $modname . ' returned incorrect staus - must be an array!'); } } else { $unsupported_mods[] = $mod; } } else { debugging('Missing lib.php in ' . $modname . ' module!'); } } } // mention unsupported mods if (!empty($unsupported_mods)) { foreach ($unsupported_mods as $mod) { $status[] = array('component' => get_string('modulenameplural', $mod->name), 'item' => '', 'error' => get_string('resetnotimplemented')); } } $componentstr = get_string('gradebook', 'grades'); // reset gradebook if (!empty($data->reset_gradebook_items)) { remove_course_grades($data->courseid, false); grade_grab_course_grades($data->courseid); grade_regrade_final_grades($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removeallcourseitems', 'grades'), 'error' => false); } else { if (!empty($data->reset_gradebook_grades)) { grade_course_reset($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removeallcoursegrades', 'grades'), 'error' => false); } } return $status; }
/** * Initialise the iterator * @return boolean success */ public function init() { global $CFG, $DB; $this->close(); grade_regrade_final_grades($this->course->id); $course_item = grade_item::fetch_course_item($this->course->id); if ($course_item->needsupdate) { // can not calculate all final grades - sorry return false; } list($gradebookroles_sql, $params) = $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr0'); $relatedcontexts = get_related_contexts_string(get_context_instance(CONTEXT_COURSE, $this->course->id)); if ($this->groupid) { $groupsql = "INNER JOIN {groups_members} gm ON gm.userid = u.id"; $groupwheresql = "AND gm.groupid = :groupid"; // $params contents: gradebookroles $params['groupid'] = $this->groupid; } else { $groupsql = ""; $groupwheresql = ""; } if (empty($this->sortfield1)) { // we must do some sorting even if not specified $ofields = ", u.id AS usrt"; $order = "usrt ASC"; } else { $ofields = ", u.$this->sortfield1 AS usrt1"; $order = "usrt1 $this->sortorder1"; if (!empty($this->sortfield2)) { $ofields .= ", u.$this->sortfield2 AS usrt2"; $order .= ", usrt2 $this->sortorder2"; } if ($this->sortfield1 != 'id' and $this->sortfield2 != 'id') { // user order MUST be the same in both queries, // must include the only unique user->id if not already present $ofields .= ", u.id AS usrt"; $order .= ", usrt ASC"; } } // $params contents: gradebookroles and groupid (for $groupwheresql) $users_sql = "SELECT u.* $ofields FROM {user} u INNER JOIN {role_assignments} ra ON u.id = ra.userid $groupsql WHERE u.deleted=0 AND ra.roleid $gradebookroles_sql AND ra.contextid $relatedcontexts $groupwheresql ORDER BY $order"; $this->users_rs = $DB->get_recordset_sql($users_sql, $params); if (!empty($this->grade_items)) { $itemids = array_keys($this->grade_items); list($itemidsql, $grades_params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED, 'items0'); $params = array_merge($params, $grades_params); // $params contents: gradebookroles, groupid (for $groupwheresql) and itemids $grades_sql = "SELECT g.* $ofields FROM {grade_grades} g INNER JOIN {user} u ON g.userid = u.id INNER JOIN {role_assignments} ra ON u.id = ra.userid $groupsql WHERE ra.roleid $gradebookroles_sql AND ra.contextid $relatedcontexts $groupwheresql AND g.itemid $itemidsql ORDER BY $order, g.itemid ASC"; $this->grades_rs = $DB->get_recordset_sql($grades_sql, $params); } else { $this->grades_rs = false; } return true; }
/** * Profile report callback. * * @param object $course The course. * @param object $user The user. * @param boolean $viewasuser True when we are viewing this as the targetted user sees it. */ function grade_report_user_profilereport($course, $user, $viewasuser = false) { global $OUTPUT; if (!empty($course->showgrades)) { $context = context_course::instance($course->id); //first make sure we have proper final grades - this must be done before constructing of the grade tree grade_regrade_final_grades($course->id); /// return tracking object $gpr = new grade_plugin_return(array('type' => 'report', 'plugin' => 'user', 'courseid' => $course->id, 'userid' => $user->id)); // Create a report instance $report = new grade_report_user($course->id, $gpr, $context, $user->id, $viewasuser); // print the page echo '<div class="grade-report-user">'; // css fix to share styles with real report page echo $OUTPUT->heading(get_string('pluginname', 'gradereport_user') . ' - ' . fullname($report->user)); if ($report->fill_table()) { echo $report->print_table(true); } echo '</div>'; } }
protected function after_execute() { global $DB; $conditions = array( 'backupid' => $this->get_restoreid(), 'itemname' => 'grade_item'//, //'itemid' => $itemid ); $rs = $DB->get_recordset('backup_ids_temp', $conditions); if (!empty($rs)) { foreach($rs as $grade_item_backup) { $updateobj = new stdclass(); $updateobj->id = $grade_item_backup->newitemid; //if this is an activity grade item that needs to be put back in its correct category if (!empty($grade_item_backup->parentitemid)) { $updateobj->categoryid = $this->get_mappingid('grade_category', $grade_item_backup->parentitemid); } else { //mark course and category items as needing to be recalculated $updateobj->needsupdate=1; } $DB->update_record('grade_items', $updateobj); } } $rs->close(); //need to correct the grade category path and parent $conditions = array( 'courseid' => $this->get_courseid() ); $grade_category = new stdclass(); $rs = $DB->get_recordset('grade_categories', $conditions); if (!empty($rs)) { //get all the parents correct first as grade_category::build_path() loads category parents from the DB foreach($rs as $gc) { if (!empty($gc->parent)) { $grade_category->id = $gc->id; $grade_category->parent = $this->get_mappingid('grade_category', $gc->parent); $DB->update_record('grade_categories', $grade_category); } } } if (isset($grade_category->parent)) { unset($grade_category->parent); } $rs->close(); $rs = $DB->get_recordset('grade_categories', $conditions); if (!empty($rs)) { //now we can rebuild all the paths foreach($rs as $gc) { $grade_category->id = $gc->id; $grade_category->path = grade_category::build_path($gc); $DB->update_record('grade_categories', $grade_category); } } $rs->close(); //Restore marks items as needing update. Update everything now. grade_regrade_final_grades($this->get_courseid()); }
/** * This function will empty a course of user data. * It will retain the activities and the structure of the course. * * @param object $data an object containing all the settings including courseid (without magic quotes) * @return array status array of array component, item, error */ function reset_course_userdata($data) { global $CFG, $DB; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->libdir . '/completionlib.php'; require_once $CFG->dirroot . '/group/lib.php'; $data->courseid = $data->id; $context = context_course::instance($data->courseid); $eventparams = array('context' => $context, 'courseid' => $data->id, 'other' => array('reset_options' => (array) $data)); $event = \core\event\course_reset_started::create($eventparams); $event->trigger(); // Calculate the time shift of dates. if (!empty($data->reset_start_date)) { // Time part of course startdate should be zero. $data->timeshift = $data->reset_start_date - usergetmidnight($data->reset_start_date_old); } else { $data->timeshift = 0; } // Result array: component, item, error. $status = array(); // Start the resetting. $componentstr = get_string('general'); // Move the course start time. if (!empty($data->reset_start_date) and $data->timeshift) { // Change course start data. $DB->set_field('course', 'startdate', $data->reset_start_date, array('id' => $data->courseid)); // Update all course and group events - do not move activity events. $updatesql = "UPDATE {event}\n SET timestart = timestart + ?\n WHERE courseid=? AND instance=0"; $DB->execute($updatesql, array($data->timeshift, $data->courseid)); // Update any date activity restrictions. if ($CFG->enableavailability) { \availability_date\condition::update_all_dates($data->courseid, $data->timeshift); } $status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false); } if (!empty($data->reset_end_date)) { // If the user set a end date value respect it. $DB->set_field('course', 'enddate', $data->reset_end_date, array('id' => $data->courseid)); } else { if ($data->timeshift > 0 && $data->reset_end_date_old) { // If there is a time shift apply it to the end date as well. $enddate = $data->reset_end_date_old + $data->timeshift; $DB->set_field('course', 'enddate', $enddate, array('id' => $data->courseid)); } } if (!empty($data->reset_events)) { $DB->delete_records('event', array('courseid' => $data->courseid)); $status[] = array('component' => $componentstr, 'item' => get_string('deleteevents', 'calendar'), 'error' => false); } if (!empty($data->reset_notes)) { require_once $CFG->dirroot . '/notes/lib.php'; note_delete_all($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deletenotes', 'notes'), 'error' => false); } if (!empty($data->delete_blog_associations)) { require_once $CFG->dirroot . '/blog/lib.php'; blog_remove_associations_for_course($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deleteblogassociations', 'blog'), 'error' => false); } if (!empty($data->reset_completion)) { // Delete course and activity completion information. $course = $DB->get_record('course', array('id' => $data->courseid)); $cc = new completion_info($course); $cc->delete_all_completion_data(); $status[] = array('component' => $componentstr, 'item' => get_string('deletecompletiondata', 'completion'), 'error' => false); } if (!empty($data->reset_competency_ratings)) { \core_competency\api::hook_course_reset_competency_ratings($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deletecompetencyratings', 'core_competency'), 'error' => false); } $componentstr = get_string('roles'); if (!empty($data->reset_roles_overrides)) { $children = $context->get_child_contexts(); foreach ($children as $child) { $DB->delete_records('role_capabilities', array('contextid' => $child->id)); } $DB->delete_records('role_capabilities', array('contextid' => $context->id)); // Force refresh for logged in users. $context->mark_dirty(); $status[] = array('component' => $componentstr, 'item' => get_string('deletecourseoverrides', 'role'), 'error' => false); } if (!empty($data->reset_roles_local)) { $children = $context->get_child_contexts(); foreach ($children as $child) { role_unassign_all(array('contextid' => $child->id)); } // Force refresh for logged in users. $context->mark_dirty(); $status[] = array('component' => $componentstr, 'item' => get_string('deletelocalroles', 'role'), 'error' => false); } // First unenrol users - this cleans some of related user data too, such as forum subscriptions, tracking, etc. $data->unenrolled = array(); if (!empty($data->unenrol_users)) { $plugins = enrol_get_plugins(true); $instances = enrol_get_instances($data->courseid, true); foreach ($instances as $key => $instance) { if (!isset($plugins[$instance->enrol])) { unset($instances[$key]); continue; } } foreach ($data->unenrol_users as $withroleid) { if ($withroleid) { $sql = "SELECT ue.*\n FROM {user_enrolments} ue\n JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)\n JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid)\n JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.roleid = :roleid AND ra.userid = ue.userid)"; $params = array('courseid' => $data->courseid, 'roleid' => $withroleid, 'courselevel' => CONTEXT_COURSE); } else { // Without any role assigned at course context. $sql = "SELECT ue.*\n FROM {user_enrolments} ue\n JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)\n JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid)\n LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = ue.userid)\n WHERE ra.id IS null"; $params = array('courseid' => $data->courseid, 'courselevel' => CONTEXT_COURSE); } $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $ue) { if (!isset($instances[$ue->enrolid])) { continue; } $instance = $instances[$ue->enrolid]; $plugin = $plugins[$instance->enrol]; if (!$plugin->allow_unenrol($instance) and !$plugin->allow_unenrol_user($instance, $ue)) { continue; } $plugin->unenrol_user($instance, $ue->userid); $data->unenrolled[$ue->userid] = $ue->userid; } $rs->close(); } } if (!empty($data->unenrolled)) { $status[] = array('component' => $componentstr, 'item' => get_string('unenrol', 'enrol') . ' (' . count($data->unenrolled) . ')', 'error' => false); } $componentstr = get_string('groups'); // Remove all group members. if (!empty($data->reset_groups_members)) { groups_delete_group_members($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removegroupsmembers', 'group'), 'error' => false); } // Remove all groups. if (!empty($data->reset_groups_remove)) { groups_delete_groups($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroups', 'group'), 'error' => false); } // Remove all grouping members. if (!empty($data->reset_groupings_members)) { groups_delete_groupings_groups($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('removegroupingsmembers', 'group'), 'error' => false); } // Remove all groupings. if (!empty($data->reset_groupings_remove)) { groups_delete_groupings($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroupings', 'group'), 'error' => false); } // Look in every instance of every module for data to delete. $unsupportedmods = array(); if ($allmods = $DB->get_records('modules')) { foreach ($allmods as $mod) { $modname = $mod->name; $modfile = $CFG->dirroot . '/mod/' . $modname . '/lib.php'; $moddeleteuserdata = $modname . '_reset_userdata'; // Function to delete user data. if (file_exists($modfile)) { if (!$DB->count_records($modname, array('course' => $data->courseid))) { continue; // Skip mods with no instances. } include_once $modfile; if (function_exists($moddeleteuserdata)) { $modstatus = $moddeleteuserdata($data); if (is_array($modstatus)) { $status = array_merge($status, $modstatus); } else { debugging('Module ' . $modname . ' returned incorrect staus - must be an array!'); } } else { $unsupportedmods[] = $mod; } } else { debugging('Missing lib.php in ' . $modname . ' module!'); } } } // Mention unsupported mods. if (!empty($unsupportedmods)) { foreach ($unsupportedmods as $mod) { $status[] = array('component' => get_string('modulenameplural', $mod->name), 'item' => '', 'error' => get_string('resetnotimplemented')); } } $componentstr = get_string('gradebook', 'grades'); // Reset gradebook,. if (!empty($data->reset_gradebook_items)) { remove_course_grades($data->courseid, false); grade_grab_course_grades($data->courseid); grade_regrade_final_grades($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removeallcourseitems', 'grades'), 'error' => false); } else { if (!empty($data->reset_gradebook_grades)) { grade_course_reset($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removeallcoursegrades', 'grades'), 'error' => false); } } // Reset comments. if (!empty($data->reset_comments)) { require_once $CFG->dirroot . '/comment/lib.php'; comment::reset_course_page_comments($context); } $event = \core\event\course_reset_ended::create($eventparams); $event->trigger(); return $status; }
function backup_gradebook_info($bf, $preferences) { global $CFG; require_once $CFG->libdir . '/gradelib.php'; //first make sure items are properly sorted and everything is ok grade_category::fetch_course_tree($preferences->backup_course, true); grade_regrade_final_grades($preferences->backup_course); $status = true; // see if ALL grade items of type mod of this course are being backed up // if not, we do not need to backup grade category and associated grade items/grades $backupall = true; if ($grade_items = get_records_sql("SELECT *\n FROM {$CFG->prefix}grade_items\n WHERE courseid = {$preferences->backup_course}\n AND itemtype = 'mod'")) { foreach ($grade_items as $grade_item) { // get module information // if some activities not selected, we do not backup categories at all if (!backup_mod_selected($preferences, $grade_item->itemmodule, $grade_item->iteminstance)) { $backupall = false; break; } } unset($grade_items); //free memory } //Gradebook header fwrite($bf, start_tag("GRADEBOOK", 2, true)); $status = backup_gradebook_outcomes_info($bf, $preferences); $status = backup_gradebook_grade_letters_info($bf, $preferences); // Now backup grade_item (inside grade_category) if ($backupall) { $status = backup_gradebook_category_info($bf, $preferences); } $status = backup_gradebook_item_info($bf, $preferences, $backupall); // backup gradebook histories (only if grade history is enabled and selected) if (empty($CFG->disablegradehistory) && $preferences->backup_gradebook_history) { $status = backup_gradebook_outcomes_history($bf, $preferences); $status = backup_gradebook_categories_history_info($bf, $preferences); $status = backup_gradebook_items_history_info($bf, $preferences); $status = backup_gradebook_grades_history_info($bf, $preferences); } //Gradebook footer $status = fwrite($bf, end_tag("GRADEBOOK", 2, true)); return $status; }
/** * Print warning about changed grades during upgrade to 2.8. * * @param int $courseid The current course id. * @param context $context The course context. * @param string $thispage The relative path for the current page. E.g. /grade/report/user/index.php * @param boolean $return return as string * * @return nothing or string if $return true */ function print_natural_aggregation_upgrade_notice($courseid, $context, $thispage, $return = false) { global $CFG, $OUTPUT; $html = ''; // Do not do anything if they cannot manage the grades of this course. if (!has_capability('moodle/grade:manage', $context)) { return $html; } $hidesubcatswarning = optional_param('seenaggregatesubcatsupgradedgrades', false, PARAM_BOOL) && confirm_sesskey(); $showsubcatswarning = get_config('core', 'show_aggregatesubcats_upgrade_' . $courseid); $hidenaturalwarning = optional_param('seensumofgradesupgradedgrades', false, PARAM_BOOL) && confirm_sesskey(); $shownaturalwarning = get_config('core', 'show_sumofgrades_upgrade_' . $courseid); $hideminmaxwarning = optional_param('seenminmaxupgradedgrades', false, PARAM_BOOL) && confirm_sesskey(); $showminmaxwarning = get_config('core', 'show_min_max_grades_changed_' . $courseid); $useminmaxfromgradeitem = optional_param('useminmaxfromgradeitem', false, PARAM_BOOL) && confirm_sesskey(); $useminmaxfromgradegrade = optional_param('useminmaxfromgradegrade', false, PARAM_BOOL) && confirm_sesskey(); $minmaxtouse = grade_get_setting($courseid, 'minmaxtouse', $CFG->grade_minmaxtouse); $gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $courseid); $acceptgradebookchanges = optional_param('acceptgradebookchanges', false, PARAM_BOOL) && confirm_sesskey(); // Hide the warning if the user told it to go away. if ($hidenaturalwarning) { hide_natural_aggregation_upgrade_notice($courseid); } // Hide the warning if the user told it to go away. if ($hidesubcatswarning) { hide_aggregatesubcats_upgrade_notice($courseid); } // Hide the min/max warning if the user told it to go away. if ($hideminmaxwarning) { grade_hide_min_max_grade_upgrade_notice($courseid); $showminmaxwarning = false; } if ($useminmaxfromgradegrade) { // Revert to the new behaviour, we now use the grade_grade for min/max. grade_upgrade_use_min_max_from_grade_grade($courseid); grade_hide_min_max_grade_upgrade_notice($courseid); $showminmaxwarning = false; } else { if ($useminmaxfromgradeitem) { // Apply the new logic, we now use the grade_item for min/max. grade_upgrade_use_min_max_from_grade_item($courseid); grade_hide_min_max_grade_upgrade_notice($courseid); $showminmaxwarning = false; } } if (!$hidenaturalwarning && $shownaturalwarning) { $message = get_string('sumofgradesupgradedgrades', 'grades'); $hidemessage = get_string('upgradedgradeshidemessage', 'grades'); $urlparams = array('id' => $courseid, 'seensumofgradesupgradedgrades' => true, 'sesskey' => sesskey()); $goawayurl = new moodle_url($thispage, $urlparams); $goawaybutton = $OUTPUT->single_button($goawayurl, $hidemessage, 'get'); $html .= $OUTPUT->notification($message, 'notifysuccess'); $html .= $goawaybutton; } if (!$hidesubcatswarning && $showsubcatswarning) { $message = get_string('aggregatesubcatsupgradedgrades', 'grades'); $hidemessage = get_string('upgradedgradeshidemessage', 'grades'); $urlparams = array('id' => $courseid, 'seenaggregatesubcatsupgradedgrades' => true, 'sesskey' => sesskey()); $goawayurl = new moodle_url($thispage, $urlparams); $goawaybutton = $OUTPUT->single_button($goawayurl, $hidemessage, 'get'); $html .= $OUTPUT->notification($message, 'notifysuccess'); $html .= $goawaybutton; } if ($showminmaxwarning) { $hidemessage = get_string('upgradedgradeshidemessage', 'grades'); $urlparams = array('id' => $courseid, 'seenminmaxupgradedgrades' => true, 'sesskey' => sesskey()); $goawayurl = new moodle_url($thispage, $urlparams); $hideminmaxbutton = $OUTPUT->single_button($goawayurl, $hidemessage, 'get'); $moreinfo = html_writer::link(get_docs_url(get_string('minmaxtouse_link', 'grades')), get_string('moreinfo'), array('target' => '_blank')); if ($minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_ITEM) { // Show the message that there were min/max issues that have been resolved. $message = get_string('minmaxupgradedgrades', 'grades') . ' ' . $moreinfo; $revertmessage = get_string('upgradedminmaxrevertmessage', 'grades'); $urlparams = array('id' => $courseid, 'useminmaxfromgradegrade' => true, 'sesskey' => sesskey()); $reverturl = new moodle_url($thispage, $urlparams); $revertbutton = $OUTPUT->single_button($reverturl, $revertmessage, 'get'); $html .= $OUTPUT->notification($message); $html .= $revertbutton . $hideminmaxbutton; } else { if ($minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_GRADE) { // Show the warning that there are min/max issues that have not be resolved. $message = get_string('minmaxupgradewarning', 'grades') . ' ' . $moreinfo; $fixmessage = get_string('minmaxupgradefixbutton', 'grades'); $urlparams = array('id' => $courseid, 'useminmaxfromgradeitem' => true, 'sesskey' => sesskey()); $fixurl = new moodle_url($thispage, $urlparams); $fixbutton = $OUTPUT->single_button($fixurl, $fixmessage, 'get'); $html .= $OUTPUT->notification($message); $html .= $fixbutton . $hideminmaxbutton; } } } if ($gradebookcalculationsfreeze) { if ($acceptgradebookchanges) { // Accept potential changes in grades caused by extra credit bug MDL-49257. hide_gradebook_calculations_freeze_notice($courseid); $courseitem = grade_item::fetch_course_item($courseid); $courseitem->force_regrading(); grade_regrade_final_grades($courseid); $html .= $OUTPUT->notification(get_string('gradebookcalculationsuptodate', 'grades'), 'notifysuccess'); } else { // Show the warning that there may be extra credit weights problems. $a = new stdClass(); $a->gradebookversion = $gradebookcalculationsfreeze; if (preg_match('/(\\d{8,})/', $CFG->release, $matches)) { $a->currentversion = $matches[1]; } else { $a->currentversion = $CFG->release; } $a->url = get_docs_url('Gradebook_calculation_changes'); $message = get_string('gradebookcalculationswarning', 'grades', $a); $fixmessage = get_string('gradebookcalculationsfixbutton', 'grades'); $urlparams = array('id' => $courseid, 'acceptgradebookchanges' => true, 'sesskey' => sesskey()); $fixurl = new moodle_url($thispage, $urlparams); $fixbutton = $OUTPUT->single_button($fixurl, $fixmessage, 'get'); $html .= $OUTPUT->notification($message); $html .= $fixbutton; } } if (!empty($html)) { $html = html_writer::tag('div', $html, array('class' => 'core_grades_notices')); } if ($return) { return $html; } else { echo $html; } }
/** * Updates raw grade value for given user, this is a only way to update raw * grades from external source (modules, etc.), * because it logs the change in history table and deals with final grade recalculation. * * @param int $userid the graded user * @param mixed $rawgrade float value of raw grade - false means do not change * @param string $howmodified modification source * @param string $note optional note * @param mixed $feedback teachers feedback as string - false means do not change * @param int $feedbackformat * @param int $usermodified - user which did the grading * @param int $dategraded * @param int $datesubmitted * @param object $grade object - usefull for bulk upgrades * @return boolean success */ function update_raw_grade($userid, $rawgrade = false, $source = NULL, $feedback = false, $feedbackformat = FORMAT_MOODLE, $usermodified = null, $dategraded = null, $datesubmitted = null, $grade = null) { global $USER; $result = true; // calculated grades can not be updated; course and category can not be updated because they are aggregated if (!$this->is_raw_used() or $this->gradetype == GRADE_TYPE_NONE or $this->is_locked()) { return false; } if (is_null($grade)) { //fetch from db $grade = new grade_grade(array('itemid' => $this->id, 'userid' => $userid)); } $grade->grade_item =& $this; // prevent db fetching of this grade_item if (empty($usermodified)) { $grade->usermodified = $USER->id; } else { $grade->usermodified = $usermodified; } if ($grade->is_locked()) { // do not update locked grades at all return false; } $locktime = $grade->get_locktime(); if ($locktime and $locktime < time()) { // do not update grades that should be already locked and force regrade $this->force_regrading(); return false; } $oldgrade = new object(); $oldgrade->finalgrade = $grade->finalgrade; $oldgrade->rawgrade = $grade->rawgrade; $oldgrade->rawgrademin = $grade->rawgrademin; $oldgrade->rawgrademax = $grade->rawgrademax; $oldgrade->rawscaleid = $grade->rawscaleid; $oldgrade->feedback = $grade->feedback; $oldgrade->feedbackformat = $grade->feedbackformat; // use new min and max $grade->rawgrade = $grade->rawgrade; $grade->rawgrademin = $this->grademin; $grade->rawgrademax = $this->grademax; $grade->rawscaleid = $this->scaleid; // change raw grade? if ($rawgrade !== false) { $grade->rawgrade = $rawgrade; } // empty feedback means no feedback at all if ($feedback === '') { $feedback = null; } // do we have comment from teacher? if ($feedback !== false and !$grade->is_overridden()) { $grade->feedback = $feedback; $grade->feedbackformat = $feedbackformat; } // update final grade if possible if (!$grade->is_locked() and !$grade->is_overridden()) { $grade->finalgrade = $this->adjust_raw_grade($grade->rawgrade, $grade->rawgrademin, $grade->rawgrademax); } // TODO: hack alert - create new fields for these in 2.0 $oldgrade->timecreated = $grade->timecreated; $oldgrade->timemodified = $grade->timemodified; $grade->timecreated = $datesubmitted; if ($grade->is_overridden()) { // keep original graded date - update_final_grade() sets this for overridden grades } else { if (is_null($grade->rawgrade) and is_null($grade->feedback)) { // no grade and feedback means no grading yet $grade->timemodified = null; } else { if (!empty($dategraded)) { // fine - module sends info when graded (yay!) $grade->timemodified = $dategraded; } else { if (grade_floats_different($grade->finalgrade, $oldgrade->finalgrade) or $grade->feedback !== $oldgrade->feedback) { // guess - if either grade or feedback changed set new graded date $grade->timemodified = time(); } else { //keep original graded date } } } } // end of hack alert if (empty($grade->id)) { $result = (bool) $grade->insert($source); } else { if (grade_floats_different($grade->finalgrade, $oldgrade->finalgrade) or grade_floats_different($grade->rawgrade, $oldgrade->rawgrade) or grade_floats_different($grade->rawgrademin, $oldgrade->rawgrademin) or grade_floats_different($grade->rawgrademax, $oldgrade->rawgrademax) or $grade->rawscaleid != $oldgrade->rawscaleid or $grade->feedback !== $oldgrade->feedback or $grade->feedbackformat != $oldgrade->feedbackformat or $grade->timecreated != $oldgrade->timecreated or $grade->timemodified != $oldgrade->timemodified) { $result = $grade->update($source); } else { return $result; } } if (!$result) { // something went wrong - better force final grade recalculation $this->force_regrading(); } else { if (!$this->needsupdate) { $course_item = grade_item::fetch_course_item($this->courseid); if (!$course_item->needsupdate) { if (grade_regrade_final_grades($this->courseid, $userid, $this) !== true) { $this->force_regrading(); } } } } return $result; }
/** * Initialise the iterator * * @return boolean success */ public function init() { global $CFG, $DB; $this->close(); grade_regrade_final_grades($this->course->id); $course_item = grade_item::fetch_course_item($this->course->id); if ($course_item->needsupdate) { // can not calculate all final grades - sorry return false; } $coursecontext = context_course::instance($this->course->id); $relatedcontexts = get_related_contexts_string($coursecontext); list($gradebookroles_sql, $params) = $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr'); list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, '', 0, $this->onlyactive); $params = array_merge($params, $enrolledparams); if ($this->groupid) { $groupsql = "INNER JOIN {groups_members} gm ON gm.userid = u.id"; $groupwheresql = "AND gm.groupid = :groupid"; // $params contents: gradebookroles $params['groupid'] = $this->groupid; } else { $groupsql = ""; $groupwheresql = ""; } if (empty($this->sortfield1)) { // we must do some sorting even if not specified $ofields = ", u.id AS usrt"; $order = "usrt ASC"; } else { $ofields = ", u.{$this->sortfield1} AS usrt1"; $order = "usrt1 {$this->sortorder1}"; if (!empty($this->sortfield2)) { $ofields .= ", u.{$this->sortfield2} AS usrt2"; $order .= ", usrt2 {$this->sortorder2}"; } if ($this->sortfield1 != 'id' and $this->sortfield2 != 'id') { // user order MUST be the same in both queries, // must include the only unique user->id if not already present $ofields .= ", u.id AS usrt"; $order .= ", usrt ASC"; } } $userfields = 'u.*'; $customfieldssql = ''; if ($this->allowusercustomfields && !empty($CFG->grade_export_customprofilefields)) { $customfieldscount = 0; $customfieldsarray = grade_helper::get_user_profile_fields($this->course->id, $this->allowusercustomfields); foreach ($customfieldsarray as $field) { if (!empty($field->customid)) { $customfieldssql .= "\n LEFT JOIN (SELECT * FROM {user_info_data}\n WHERE fieldid = :cf{$customfieldscount}) cf{$customfieldscount}\n ON u.id = cf{$customfieldscount}.userid"; $userfields .= ", cf{$customfieldscount}.data AS 'customfield_{$field->shortname}'"; $params['cf' . $customfieldscount] = $field->customid; $customfieldscount++; } } } // $params contents: gradebookroles and groupid (for $groupwheresql) $users_sql = "SELECT {$userfields} {$ofields}\n FROM {user} u\n JOIN ({$enrolledsql}) je ON je.id = u.id\n {$groupsql} {$customfieldssql}\n JOIN (\n SELECT DISTINCT ra.userid\n FROM {role_assignments} ra\n WHERE ra.roleid {$gradebookroles_sql}\n AND ra.contextid {$relatedcontexts}\n ) rainner ON rainner.userid = u.id\n WHERE u.deleted = 0\n {$groupwheresql}\n ORDER BY {$order}"; $this->users_rs = $DB->get_recordset_sql($users_sql, $params); if (!empty($this->grade_items)) { $itemids = array_keys($this->grade_items); list($itemidsql, $grades_params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED, 'items'); $params = array_merge($params, $grades_params); // $params contents: gradebookroles, enrolledparams, groupid (for $groupwheresql) and itemids $grades_sql = "SELECT g.* {$ofields}\n FROM {grade_grades} g\n JOIN {user} u ON g.userid = u.id\n JOIN ({$enrolledsql}) je ON je.id = u.id\n {$groupsql}\n JOIN (\n SELECT DISTINCT ra.userid\n FROM {role_assignments} ra\n WHERE ra.roleid {$gradebookroles_sql}\n AND ra.contextid {$relatedcontexts}\n ) rainner ON rainner.userid = u.id\n WHERE u.deleted = 0\n AND g.itemid {$itemidsql}\n {$groupwheresql}\n ORDER BY {$order}, g.itemid ASC"; $this->grades_rs = $DB->get_recordset_sql($grades_sql, $params); } else { $this->grades_rs = false; } return true; }
/** * Test the upgrade function for flagging courses with calculated grade item problems. */ public function test_upgrade_calculated_grade_items() { global $DB, $CFG; $this->resetAfterTest(); // Create a user. $user = $this->getDataGenerator()->create_user(); // Create a couple of courses. $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $course3 = $this->getDataGenerator()->create_course(); // Enrol the user in the courses. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $maninstance1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST); $maninstance2 = $DB->get_record('enrol', array('courseid' => $course2->id, 'enrol' => 'manual'), '*', MUST_EXIST); $maninstance3 = $DB->get_record('enrol', array('courseid' => $course3->id, 'enrol' => 'manual'), '*', MUST_EXIST); $manual = enrol_get_plugin('manual'); $manual->enrol_user($maninstance1, $user->id, $studentrole->id); $manual->enrol_user($maninstance2, $user->id, $studentrole->id); $manual->enrol_user($maninstance3, $user->id, $studentrole->id); // To create the data we need we freeze the grade book to use the old behaviour. set_config('gradebook_calculations_freeze_' . $course1->id, 20150627); set_config('gradebook_calculations_freeze_' . $course2->id, 20150627); set_config('gradebook_calculations_freeze_' . $course3->id, 20150627); $CFG->grade_minmaxtouse = 2; // Creating a category for a grade item. $gradecategory = new grade_category(); $gradecategory->fullname = 'calculated grade category'; $gradecategory->courseid = $course1->id; $gradecategory->insert(); $gradecategoryid = $gradecategory->id; // This is a manual grade item. $gradeitem = new grade_item(); $gradeitem->itemname = 'grade item one'; $gradeitem->itemtype = 'manual'; $gradeitem->categoryid = $gradecategoryid; $gradeitem->courseid = $course1->id; $gradeitem->idnumber = 'gi1'; $gradeitem->insert(); // Changing the category into a calculated grade category. $gradecategoryitem = grade_item::fetch(array('iteminstance' => $gradecategory->id)); $gradecategoryitem->calculation = '=##gi' . $gradeitem->id . '##/2'; $gradecategoryitem->update(); // Setting a grade for the student. $grade = $gradeitem->get_grade($user->id, true); $grade->finalgrade = 50; $grade->update(); // Creating all the grade_grade items. grade_regrade_final_grades($course1->id); // Updating the grade category to a new grade max and min. $gradecategoryitem->grademax = 50; $gradecategoryitem->grademin = 5; $gradecategoryitem->update(); // Different manual grade item for course 2. We are creating a course with a calculated grade item that has a grade max of // 50. The grade_grade will have a rawgrademax of 100 regardless. $gradeitem = new grade_item(); $gradeitem->itemname = 'grade item one'; $gradeitem->itemtype = 'manual'; $gradeitem->courseid = $course2->id; $gradeitem->idnumber = 'gi1'; $gradeitem->grademax = 25; $gradeitem->insert(); // Calculated grade item for course 2. $calculatedgradeitem = new grade_item(); $calculatedgradeitem->itemname = 'calculated grade'; $calculatedgradeitem->itemtype = 'manual'; $calculatedgradeitem->courseid = $course2->id; $calculatedgradeitem->calculation = '=##gi' . $gradeitem->id . '##*2'; $calculatedgradeitem->grademax = 50; $calculatedgradeitem->insert(); // Assigning a grade for the user. $grade = $gradeitem->get_grade($user->id, true); $grade->finalgrade = 10; $grade->update(); // Setting all of the grade_grade items. grade_regrade_final_grades($course2->id); // Different manual grade item for course 3. We are creating a course with a calculated grade item that has a grade max of // 50. The grade_grade will have a rawgrademax of 100 regardless. $gradeitem = new grade_item(); $gradeitem->itemname = 'grade item one'; $gradeitem->itemtype = 'manual'; $gradeitem->courseid = $course3->id; $gradeitem->idnumber = 'gi1'; $gradeitem->grademax = 25; $gradeitem->insert(); // Calculated grade item for course 2. $calculatedgradeitem = new grade_item(); $calculatedgradeitem->itemname = 'calculated grade'; $calculatedgradeitem->itemtype = 'manual'; $calculatedgradeitem->courseid = $course3->id; $calculatedgradeitem->calculation = '=##gi' . $gradeitem->id . '##*2'; $calculatedgradeitem->grademax = 50; $calculatedgradeitem->insert(); // Assigning a grade for the user. $grade = $gradeitem->get_grade($user->id, true); $grade->finalgrade = 10; $grade->update(); // Setting all of the grade_grade items. grade_regrade_final_grades($course3->id); // Need to do this first before changing the other courses, otherwise they will be flagged too early. set_config('gradebook_calculations_freeze_' . $course3->id, null); upgrade_calculated_grade_items($course3->id); $this->assertEquals(20150627, $CFG->{'gradebook_calculations_freeze_' . $course3->id}); // Change the setting back to null. set_config('gradebook_calculations_freeze_' . $course1->id, null); set_config('gradebook_calculations_freeze_' . $course2->id, null); // Run the upgrade. upgrade_calculated_grade_items(); // The setting should be set again after the upgrade. $this->assertEquals(20150627, $CFG->{'gradebook_calculations_freeze_' . $course1->id}); $this->assertEquals(20150627, $CFG->{'gradebook_calculations_freeze_' . $course2->id}); }
/** * Returns a list of grades tables for users in a course. * * @param int $courseid Course Id * @param int $userid Only this user (optional) * * @return array the grades tables * @since Moodle 2.9 */ public static function get_grades_table($courseid, $userid = 0) { global $CFG, $USER; $warnings = array(); // Validate the parameter. $params = self::validate_parameters(self::get_grades_table_parameters(), array('courseid' => $courseid, 'userid' => $userid)); // Compact/extract functions are not recommended. $courseid = $params['courseid']; $userid = $params['userid']; // Function get_course internally throws an exception if the course doesn't exist. $course = get_course($courseid); $context = context_course::instance($courseid); self::validate_context($context); // Specific capabilities. require_capability('gradereport/user:view', $context); $user = null; if (empty($userid)) { require_capability('moodle/grade:viewall', $context); } else { $user = core_user::get_user($userid, '*', MUST_EXIST); } $access = false; if (has_capability('moodle/grade:viewall', $context)) { // Can view all course grades. $access = true; } else { if ($userid == $USER->id and has_capability('moodle/grade:view', $context) and $course->showgrades) { // View own grades. $access = true; } } if (!$access) { throw new moodle_exception('nopermissiontoviewgrades', 'error'); } // Require files here to save some memory in case validation fails. require_once $CFG->dirroot . '/group/lib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/grade/lib.php'; require_once $CFG->dirroot . '/grade/report/user/lib.php'; // Force regrade to update items marked as 'needupdate'. grade_regrade_final_grades($course->id); $gpr = new grade_plugin_return(array('type' => 'report', 'plugin' => 'user', 'courseid' => $courseid, 'userid' => $userid)); $tables = array(); // Just one user. if ($user) { $report = new grade_report_user($courseid, $gpr, $context, $userid); $report->fill_table(); $tables[] = array('courseid' => $courseid, 'userid' => $user->id, 'userfullname' => fullname($user), 'maxdepth' => $report->maxdepth, 'tabledata' => $report->tabledata); } else { $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol); $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol); $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $context); $gui = new graded_users_iterator($course); $gui->require_active_enrolment($showonlyactiveenrol); $gui->init(); while ($userdata = $gui->next_user()) { $currentuser = $userdata->user; $report = new grade_report_user($courseid, $gpr, $context, $currentuser->id); $report->fill_table(); $tables[] = array('courseid' => $courseid, 'userid' => $currentuser->id, 'userfullname' => fullname($currentuser), 'maxdepth' => $report->maxdepth, 'tabledata' => $report->tabledata); } $gui->close(); } $result = array(); $result['tables'] = $tables; $result['warnings'] = $warnings; return $result; }
function RWSAUQuiz() { global $CFG; global $DB; global $RWSLB; global $RWSUID; RWSCMAuth(); RWSCRAuth(); RWSCMUSvc(); RWSCMMaint(); $r_pm = RWSGSOpt("quizid", PARAM_ALPHANUM); if ($r_pm === false || strlen($r_pm) == 0) { RWSSErr("2067"); } $r_qzmi = intval($r_pm); $r_cmod = RWSCMUQuiz($r_qzmi); $r_sfl = RWSGSOpt("sfile", RWSPRF); if ($r_sfl === false) { $r_sn = RWSGSOpt("sname", PARAM_FILE); $r_sd = RWSGSOpt("sdata", PARAM_NOTAGS); $r_ecd = true; } else { $r_sn = $r_sfl->filename; $r_sd = $r_sfl->filedata; $r_ecd = false; } $r_imp = false; if ($r_sd !== false && strlen($r_sd) > 0) { if ($r_sn === false || strlen($r_sn) == 0) { RWSSErr("2075"); } $r_sn = clean_filename($r_sn); $r_imp = true; } $r_cid = $r_cmod->course; $r_crs = RWSCMUCourse($r_cid, true); $r_mr = $DB->get_record("modules", array("id" => $r_cmod->module)); if ($r_mr === false) { RWSSErr("2043"); } $r_qiz = $DB->get_record($r_mr->name, array("id" => $r_cmod->instance)); if ($r_qiz === false) { RWSSErr("2044"); } $r_ren = false; $r_pm = RWSGSOpt("rename", PARAM_TEXT); if ($r_pm !== false && strlen($r_pm) > 0) { $r_ren = trim(clean_text(strip_tags($r_pm, "<lang><span>"))); $r_qiz->name = $r_ren; } if ($r_ren === false) { if ($r_sd === false || strlen($r_sd) == 0) { RWSSErr("2080"); } } $r_sec = $DB->get_record("course_sections", array("id" => $r_cmod->section)); if ($r_sec === false) { RWSSErr("2079"); } $r_qiz->coursemodule = $r_cmod->id; $r_qiz->section = $r_sec->section; $r_qiz->visible = $r_cmod->visible; $r_qiz->cmidnumber = $r_cmod->idnumber; $r_qiz->groupmode = groups_get_activity_groupmode($r_cmod); $r_qiz->groupingid = $r_cmod->groupingid; $r_qiz->groupmembersonly = $r_cmod->groupmembersonly; $r_qiz->course = $r_cid; $r_qiz->module = $r_mr->id; $r_qiz->modulename = $r_mr->name; $r_qiz->instance = $r_cmod->instance; if (respondusws_floatcompare($CFG->version, 2011120500.0, 2) >= 0) { $r_qiz->showdescription = 0; } $r_cpl = new completion_info($r_crs); if ($r_cpl->is_enabled()) { $r_qiz->completion = $r_cmod->completion; $r_qiz->completionview = $r_cmod->completionview; $r_qiz->completionexpected = $r_cmod->completionexpected; $r_qiz->completionusegrade = is_null($r_cmod->completiongradeitemnumber) ? 0 : 1; } if ($CFG->enableavailability) { $r_qiz->availablefrom = $r_cmod->availablefrom; $r_qiz->availableuntil = $r_cmod->availableuntil; if ($r_qiz->availableuntil) { $r_qiz->availableuntil = strtotime("23:59:59", $r_qiz->availableuntil); } $r_qiz->showavailability = $r_cmod->showavailability; } $r_its = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $r_qiz->modulename, 'iteminstance' => $r_qiz->instance, 'courseid' => $r_cid)); if ($r_its) { foreach ($r_its as $r_it) { if (!empty($r_it->outcomeid)) { $r_qiz->{'outcome_' . $r_it->outcomeid} = 1; } } $r_gc = false; foreach ($r_its as $r_it) { if ($r_gc === false) { $r_gc = $r_it->categoryid; continue; } if ($r_gc != $r_it->categoryid) { $r_gc = false; break; } } if ($r_gc !== false) { $r_qiz->gradecat = $r_gc; } } if ($r_imp) { RWSIQSet($r_qiz, $r_sn, $r_sd, $r_ecd); } $DB->update_record("course_modules", $r_qiz); if (is_null($r_qiz->quizpassword) && !is_null($r_qiz->password)) { $r_qiz->quizpassword = $r_qiz->password; } $r_res = quiz_update_instance($r_qiz); if (!$r_res || is_string($r_res)) { RWSSErr("2081"); } RWSSLBSet($r_qiz); set_coursemodule_visible($r_qzmi, $r_qiz->visible); if (isset($r_qiz->cmidnumber)) { set_coursemodule_idnumber($r_qzmi, $r_qiz->cmidnumber); } RWSUQGrades($r_qiz); if ($r_cpl->is_enabled() && !empty($r_qiz->completionunlocked)) { $r_cpl->reset_all_state($r_qiz); } if (respondusws_floatcompare($CFG->version, 2014051200, 2) >= 0) { $r_qiz->modname = $r_qiz->modulename; $r_qiz->id = $r_qiz->coursemodule; \core\event\course_module_updated::create_from_cm($r_qiz)->trigger(); } else { $r_evt = new stdClass(); $r_evt->modulename = $r_qiz->modulename; $r_evt->name = $r_qiz->name; $r_evt->cmid = $r_qiz->coursemodule; $r_evt->courseid = $r_qiz->course; $r_evt->userid = $RWSUID; events_trigger("mod_updated", $r_evt); } rebuild_course_cache($r_cid); grade_regrade_final_grades($r_cid); if ($RWSLB->mex || $RWSLB->bex) { if ($RWSLB->mok) { if ($RWSLB->perr) { RWSSWarn("3003"); } } else { if ($RWSLB->bok) { if ($RWSLB->perr) { RWSSWarn("3003"); } } else { RWSSWarn("3001"); } } } else { RWSSWarn("3000"); } RWSSStat("1004"); }
function generate_jwc_xml($jwc_courses, $export_users, $include_cats = false, $dryrun = true) { global $course, $output, $jwc, $DB, $USER, $nonexist_users; if ($include_cats) { $heading = '导出分项成绩及总分到教务处'; } else { $heading = '导出总分到教务处'; } if ($dryrun) { $heading .= '(模拟)'; } else { $heading .= '(正式)'; } echo $output->heading($heading); //first make sure we have proper final grades - this must be done before constructing of the grade tree grade_regrade_final_grades($course->id); // 获得成绩类别和项信息 $tree = new grade_tree($course->id, true, true); $levels = $tree->get_levels(); // 总分 $total_item = normalize_grade_item($levels[0][0]['object']->grade_item); $sub_items = array(); $extra_items = array(); $items = array(); // 顶级成绩分类和项 if (array_key_exists(1, $levels) && $include_cats) { foreach ($levels[1] as $element) { if ($element['type'] == 'item') { $grade_item = normalize_grade_item($element['object']); } else { if ($element['type'] == 'category') { $tmp = array_pop($element['children']); $grade_item = normalize_grade_item($tmp['object']); //用类别名做成绩名 $grade_item->itemname = $element['object']->fullname; } else { // ignore unused fillers continue; } } if ($grade_item->grademax <= 0) { // 不计分成绩项/类别 continue; } if ($grade_item->aggregationcoef) { // 额外加分 $extra_items[$grade_item->id] = $grade_item; } else { $sub_items[$grade_item->id] = $grade_item; } } } /// 验证成绩项是否符合教务处要求 $result = true; // 总成绩满分必须是100分 if ($total_item->grademax != MAX_TOTAL_GRADE) { echo $output->require_max_total_grade($total_item->grademax); $result = false; } if ($include_cats) { // 总成绩算法必须是“简单加权平均分” $total_aggregation = $levels[0][0]['object']->aggregation; if ($total_aggregation != GRADE_AGGREGATE_WEIGHTED_MEAN2 and $total_aggregation != GRADE_AGGREGATE_SUM) { echo $output->require_aggregation($total_aggregation); $result = false; } // 子成绩项权重和必须为100 // 所有非加分的分项相加为100,才合法,除非不包含子类别 $weight_sum = 0; foreach ($sub_items as $item) { $weight_sum += $item->grademax; } if ($include_cats and $weight_sum != MAX_TOTAL_GRADE) { echo $output->require_100_weight($weight_sum); $result = false; } // 子成绩项数量不能超过8 if (count($sub_items) > MAX_SUB_GRADE_COUNT) { echo $output->require_max_subitems(count($sub_items)); $result = false; } // 加分成绩项数量不能超过2 if (count($extra_items) > MAX_EXTRA_SUB_GRADE_COUNT) { echo $output->require_max_extraitems(count($extra_items)); $result = false; } } if (!$result) { echo $output->modify_items_link(); return false; } $xml = new gradebook_xml(); if ($dryrun) { echo $output->box_start(); echo $output->heading('可导出成绩项', 3); } $itemtable = new html_table(); $itemtable->head = array('成绩分项名称', '权重', '加分'); foreach ($sub_items as $item) { $itemtable->data[] = new html_table_row(array($item->itemname, $item->grademax . '%', '否')); $xml->add_weight_item($item->id, $item->itemname, $item->grademax, $item->grademax); } foreach ($extra_items as $item) { $itemtable->data[] = new html_table_row(array($item->itemname, $item->grademax . '%', '是')); $xml->add_weight_item($item->id, $item->itemname, $item->grademax, $item->grademax, true); } $itemtable->data[] = new html_table_row(array($total_item->itemname, $total_item->grademax . '%', '-')); if ($dryrun) { echo html_writer::table($itemtable); } // 本地不存在的用户 if (!empty($nonexist_users)) { echo $output->heading('教务处有记录而本站无对应用户的学生', 3); $usertable = new html_table(); $usertable->head = array('序号', '姓名', '学号'); $count = 0; foreach ($nonexist_users as $user) { $row = array(); $count++; $row[] = new html_table_cell($count); $row[] = new html_table_cell($user->name); $row[] = new html_table_cell($user->code); $usertable->data[] = new html_table_row($row); } echo html_writer::table($usertable); } // 用户成绩 if ($dryrun) { echo $output->heading('可导出成绩', 3); } $items = $sub_items + $extra_items; $items[$total_item->id] = $total_item; $geub = new grade_export_update_buffer(); $gui = new graded_users_iterator($course, $items); $gui->init(); $usertable = new html_table(); $usertable->head = array('序号', '姓名', '学号'); foreach ($items as $item) { $usertable->head[] = $item->itemname; } $count = 0; while ($userdata = $gui->next_user()) { $user = $userdata->user; if ($user->auth != 'cas' || empty($user->idnumber)) { // 非cas用户成绩不可导出 continue; } if (!array_key_exists($user->id, $export_users)) { // 教务处无记录用户不导出 continue; } $row = array(); $count++; $row[] = new html_table_cell($count); $row[] = new html_table_cell($user->firstname); $row[] = new html_table_cell($user->idnumber); $grades = array(); foreach ($userdata->grades as $itemid => $grade) { if ($itemid == $total_item->id) { // 总分 $finalgrade = round($grade->finalgrade); $grades[0] = $finalgrade; } else { $finalgrade = round($grade->finalgrade, 1); $grades[$itemid] = $finalgrade; } $row[] = new html_table_cell($finalgrade); } $xml->add_user($user->idnumber, $user->firstname, $grades); $usertable->data[] = new html_table_row($row); } $gui->close(); $geub->close(); if ($dryrun) { echo html_writer::table($usertable); echo $output->box_end(); } // 存入数据库 foreach ($jwc_courses as $jwc_course) { $xml->set_xkid($jwc_course->xkid); $new = new stdClass(); $new->xml = $xml->asXML(); $new->requestkey = md5($new->xml); $new->expiredtime = time() + KEY_EXPIRED_TIME; $new->user = $USER->id; $new->course = $course->id; if (!$dryrun) { if ($old = $DB->get_record('grade_export_jwc', array('requestkey' => $new->requestkey))) { $old->expiredtime = time() + KEY_EXPIRED_TIME; $DB->update_record('grade_export_jwc', $old); } else { $DB->insert_record('grade_export_jwc', $new); } // real export $errormsg = ''; if (!$jwc->export($jwc_course->xkid, $new->requestkey, $errormsg)) { $errormsg = textlib_get_instance()->convert($errormsg, 'gbk'); echo $output->notification('导出过程出错(' . $errormsg . ')。请将这串字符串报告给管理员:' . $new->requestkey); return false; } } } return true; }
/** * Verify that there is a valid set of grades to export. * @param $courseid int The course being exported */ function export_verify_grades($courseid) { $regraderesult = grade_regrade_final_grades($courseid); if (is_array($regraderesult)) { throw new moodle_exception('gradecantregrade', 'error', '', implode(', ', array_unique($regraderesult))); } }
/** * Updates raw grade value for given user, this is a only way to update raw * grades from external source (modules, etc.), * because it logs the change in history table and deals with final grade recalculation. * * @param int $userid the graded user * @param mixed $rawgrade float value of raw grade - false means do not change * @param string $howmodified modification source * @param string $note optional note * @param mixed $feedback teachers feedback as string - false means do not change * @param int $feedbackformat * @return boolean success */ function update_raw_grade($userid, $rawgrade = false, $source = NULL, $note = NULL, $feedback = false, $feedbackformat = FORMAT_MOODLE, $usermodified = null) { global $USER; if (empty($usermodified)) { $usermodified = $USER->id; } $result = true; // calculated grades can not be updated; course and category can not be updated because they are aggregated if ($this->is_calculated() or $this->is_outcome_item() or !$this->is_normal_item() or $this->gradetype == GRADE_TYPE_NONE or $this->is_locked()) { return false; } $grade = new grade_grade(array('itemid' => $this->id, 'userid' => $userid)); $grade->grade_item =& $this; // prevent db fetching of this grade_item $grade->usermodified = $usermodified; if ($grade->is_locked()) { // do not update locked grades at all return false; } $locktime = $grade->get_locktime(); if ($locktime and $locktime < time()) { // do not update grades that should be already locked and force regrade $this->force_regrading(); return false; } $oldgrade = new object(); $oldgrade->finalgrade = $grade->finalgrade; $oldgrade->rawgrade = $grade->rawgrade; $oldgrade->rawgrademin = $grade->rawgrademin; $oldgrade->rawgrademax = $grade->rawgrademax; $oldgrade->rawscaleid = $grade->rawscaleid; $oldgrade->feedback = $grade->feedback; $oldgrade->feedbackformat = $grade->feedbackformat; // fist copy current grademin/max and scale $grade->rawgrademin = $this->grademin; $grade->rawgrademax = $this->grademax; $grade->rawscaleid = $this->scaleid; // change raw grade? if ($rawgrade !== false) { $grade->rawgrade = $rawgrade; } // do we have comment from teacher? if ($feedback !== false) { $grade->feedback = $feedback; $grade->feedbackformat = $feedbackformat; } if (empty($grade->id)) { $result = (bool) $grade->insert($source); } else { if ($grade->finalgrade !== $oldgrade->finalgrade or $grade->rawgrade !== $oldgrade->rawgrade or $grade->rawgrademin !== $oldgrade->rawgrademin or $grade->rawgrademax !== $oldgrade->rawgrademax or $grade->rawscaleid !== $oldgrade->rawscaleid or $grade->feedback !== $oldgrade->feedback or $grade->feedbackformat !== $oldgrade->feedbackformat) { $result = $grade->update($source); } } if (!$result) { // something went wrong - better force final grade recalculation $this->force_regrading(); } else { if (!$this->needsupdate) { $course_item = grade_item::fetch_course_item($this->courseid); if (!$course_item->needsupdate) { if (!grade_regrade_final_grades($this->courseid, $userid, $this)) { $this->force_regrading(); } } else { $this->force_regrading(); } } } return $result; }
/** * Returns whether or not user received grades in main grade item for given activity. * * @param object $cm * @param int $userid * @return bool True if graded false if user not graded yet */ function grade_is_user_graded_in_activity($cm, $userid) { $grade_items = grade_get_grade_items_for_activity($cm, true); if (empty($grade_items)) { return false; } $grade_item = reset($grade_items); if ($grade_item->gradetype == GRADE_TYPE_NONE) { return false; } if ($grade_item->needsupdate) { // activity items should never fail to regrade grade_regrade_final_grades($grade_item->courseid); } if (!($grade = $grade_item->get_final($userid))) { return false; } if (is_null($grade->finalgrade)) { return false; } return true; }
/** * Common create/update module module actions that need to be processed as soon as a module is created/updaded. * For example:create grade parent category, add outcomes, rebuild caches, regrade, save plagiarism settings... * Please note this api does not trigger events as of MOODLE 2.6. Please trigger events before calling this api. * * @param object $moduleinfo the module info * @param object $course the course of the module * * @return object moduleinfo update with grading management info */ function edit_module_post_actions($moduleinfo, $course) { global $CFG; require_once $CFG->libdir . '/gradelib.php'; $modcontext = context_module::instance($moduleinfo->coursemodule); $hasgrades = plugin_supports('mod', $moduleinfo->modulename, FEATURE_GRADE_HAS_GRADE, false); $hasoutcomes = plugin_supports('mod', $moduleinfo->modulename, FEATURE_GRADE_OUTCOMES, true); // Sync idnumber with grade_item. if ($hasgrades && ($grade_item = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => $moduleinfo->modulename, 'iteminstance' => $moduleinfo->instance, 'itemnumber' => 0, 'courseid' => $course->id)))) { if ($grade_item->idnumber != $moduleinfo->cmidnumber) { $grade_item->idnumber = $moduleinfo->cmidnumber; $grade_item->update(); } } if ($hasgrades) { $items = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $moduleinfo->modulename, 'iteminstance' => $moduleinfo->instance, 'courseid' => $course->id)); } else { $items = array(); } // Create parent category if requested and move to correct parent category. if ($items and isset($moduleinfo->gradecat)) { if ($moduleinfo->gradecat == -1) { $grade_category = new grade_category(); $grade_category->courseid = $course->id; $grade_category->fullname = $moduleinfo->name; $grade_category->insert(); if ($grade_item) { $parent = $grade_item->get_parent_category(); $grade_category->set_parent($parent->id); } $moduleinfo->gradecat = $grade_category->id; } $gradecategory = $grade_item->get_parent_category(); foreach ($items as $itemid => $unused) { $items[$itemid]->set_parent($moduleinfo->gradecat); if ($itemid == $grade_item->id) { // Use updated grade_item. $grade_item = $items[$itemid]; } if (!empty($moduleinfo->add)) { if (grade_category::aggregation_uses_aggregationcoef($gradecategory->aggregation)) { if ($gradecategory->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) { $grade_item->aggregationcoef = 1; } else { $grade_item->aggregationcoef = 0; } $grade_item->update(); } } } } require_once $CFG->libdir . '/grade/grade_outcome.php'; // Add outcomes if requested. if ($hasoutcomes && ($outcomes = grade_outcome::fetch_all_available($course->id))) { $grade_items = array(); // Outcome grade_item.itemnumber start at 1000, there is nothing above outcomes. $max_itemnumber = 999; if ($items) { foreach ($items as $item) { if ($item->itemnumber > $max_itemnumber) { $max_itemnumber = $item->itemnumber; } } } foreach ($outcomes as $outcome) { $elname = 'outcome_' . $outcome->id; if (property_exists($moduleinfo, $elname) and $moduleinfo->{$elname}) { // So we have a request for new outcome grade item? if ($items) { $outcomeexists = false; foreach ($items as $item) { if ($item->outcomeid == $outcome->id) { $outcomeexists = true; break; } } if ($outcomeexists) { continue; } } $max_itemnumber++; $outcome_item = new grade_item(); $outcome_item->courseid = $course->id; $outcome_item->itemtype = 'mod'; $outcome_item->itemmodule = $moduleinfo->modulename; $outcome_item->iteminstance = $moduleinfo->instance; $outcome_item->itemnumber = $max_itemnumber; $outcome_item->itemname = $outcome->fullname; $outcome_item->outcomeid = $outcome->id; $outcome_item->gradetype = GRADE_TYPE_SCALE; $outcome_item->scaleid = $outcome->scaleid; $outcome_item->insert(); // Move the new outcome into correct category and fix sortorder if needed. if ($grade_item) { $outcome_item->set_parent($grade_item->categoryid); $outcome_item->move_after_sortorder($grade_item->sortorder); } else { if (isset($moduleinfo->gradecat)) { $outcome_item->set_parent($moduleinfo->gradecat); } } $gradecategory = $outcome_item->get_parent_category(); if ($outcomeexists == false) { if (grade_category::aggregation_uses_aggregationcoef($gradecategory->aggregation)) { if ($gradecategory->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) { $outcome_item->aggregationcoef = 1; } else { $outcome_item->aggregationcoef = 0; } $outcome_item->update(); } } } } } if (plugin_supports('mod', $moduleinfo->modulename, FEATURE_ADVANCED_GRADING, false) and has_capability('moodle/grade:managegradingforms', $modcontext)) { require_once $CFG->dirroot . '/grade/grading/lib.php'; $gradingman = get_grading_manager($modcontext, 'mod_' . $moduleinfo->modulename); $showgradingmanagement = false; foreach ($gradingman->get_available_areas() as $areaname => $aretitle) { $formfield = 'advancedgradingmethod_' . $areaname; if (isset($moduleinfo->{$formfield})) { $gradingman->set_area($areaname); $methodchanged = $gradingman->set_active_method($moduleinfo->{$formfield}); if (empty($moduleinfo->{$formfield})) { // Going back to the simple direct grading is not a reason to open the management screen. $methodchanged = false; } $showgradingmanagement = $showgradingmanagement || $methodchanged; } } // Update grading management information. $moduleinfo->gradingman = $gradingman; $moduleinfo->showgradingmanagement = $showgradingmanagement; } rebuild_course_cache($course->id, true); if ($hasgrades) { grade_regrade_final_grades($course->id); } require_once $CFG->libdir . '/plagiarismlib.php'; plagiarism_save_form_elements($moduleinfo); return $moduleinfo; }
/** * Reset all course grades, refetch from the activities and recalculate * * @param int $courseid The course to reset * @return bool success */ function grade_course_reset($courseid) { // no recalculations grade_force_full_regrading($courseid); $grade_items = grade_item::fetch_all(array('courseid' => $courseid)); foreach ($grade_items as $gid => $grade_item) { $grade_item->delete_all_grades('reset'); } //refetch all grades grade_grab_course_grades($courseid); // recalculate all grades grade_regrade_final_grades($courseid); return true; }
function test_upgrade_calculated_grade_items_regrade() { global $DB, $CFG; $this->resetAfterTest(); // Create a user. $user = $this->getDataGenerator()->create_user(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Enrol the user in the course. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $maninstance1 = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'), '*', MUST_EXIST); $manual = enrol_get_plugin('manual'); $manual->enrol_user($maninstance1, $user->id, $studentrole->id); set_config('upgrade_calculatedgradeitemsonlyregrade', 1); // Creating a category for a grade item. $gradecategory = new grade_category(); $gradecategory->fullname = 'calculated grade category'; $gradecategory->courseid = $course->id; $gradecategory->insert(); $gradecategoryid = $gradecategory->id; // This is a manual grade item. $gradeitem = new grade_item(); $gradeitem->itemname = 'grade item one'; $gradeitem->itemtype = 'manual'; $gradeitem->categoryid = $gradecategoryid; $gradeitem->courseid = $course->id; $gradeitem->idnumber = 'gi1'; $gradeitem->insert(); // Changing the category into a calculated grade category. $gradecategoryitem = grade_item::fetch(array('iteminstance' => $gradecategory->id)); $gradecategoryitem->calculation = '=##gi' . $gradeitem->id . '##/2'; $gradecategoryitem->grademax = 50; $gradecategoryitem->grademin = 15; $gradecategoryitem->update(); // Setting a grade for the student. $grade = $gradeitem->get_grade($user->id, true); $grade->finalgrade = 50; $grade->update(); grade_regrade_final_grades($course->id); $grade = grade_grade::fetch(array('itemid' => $gradecategoryitem->id, 'userid' => $user->id)); $grade->rawgrademax = 100; $grade->rawgrademin = 0; $grade->update(); $this->assertNotEquals($gradecategoryitem->grademax, $grade->rawgrademax); $this->assertNotEquals($gradecategoryitem->grademin, $grade->rawgrademin); // This is the function that we are testing. If we comment out this line, then the test fails because the grade items // are not flagged for regrading. upgrade_calculated_grade_items(); grade_regrade_final_grades($course->id); $grade = grade_grade::fetch(array('itemid' => $gradecategoryitem->id, 'userid' => $user->id)); $this->assertEquals($gradecategoryitem->grademax, $grade->rawgrademax); $this->assertEquals($gradecategoryitem->grademin, $grade->rawgrademin); }
/** * Returns grading information for given activity - optionally with users grades * Manual, course or category items can not be queried. * @param int $courseid id of course * @param string $itemtype 'mod', 'block' * @param string $itemmodule 'forum, 'quiz', etc. * @param int $iteminstance id of the item module * @param int $userid optional id of the graded user; if userid not used, returns only information about grade_item * @return array of grade information objects (scaleid, name, grade and locked status, etc.) indexed with itemnumbers */ function grade_get_grades($courseid, $itemtype, $itemmodule, $iteminstance, $userid_or_ids = 0) { global $CFG; $return = new object(); $return->items = array(); $return->outcomes = array(); $course_item = grade_item::fetch_course_item($courseid); $needsupdate = array(); if ($course_item->needsupdate) { $result = grade_regrade_final_grades($courseid); if ($result !== true) { $needsupdate = array_keys($result); } } if ($grade_items = grade_item::fetch_all(array('itemtype' => $itemtype, 'itemmodule' => $itemmodule, 'iteminstance' => $iteminstance, 'courseid' => $courseid))) { foreach ($grade_items as $grade_item) { $decimalpoints = null; if (empty($grade_item->outcomeid)) { // prepare information about grade item $item = new object(); $item->itemnumber = $grade_item->itemnumber; $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(); $item->grades = array(); 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; } if (empty($userid_or_ids)) { $userids = array(); } else { if (is_array($userid_or_ids)) { $userids = $userid_or_ids; } else { $userids = array($userid_or_ids); } } if ($userids) { $grade_grades = grade_grade::fetch_users_grades($grade_item, $userids, true); foreach ($userids as $userid) { $grade_grades[$userid]->grade_item =& $grade_item; $grade = new object(); $grade->grade = $grade_grades[$userid]->finalgrade; $grade->locked = $grade_grades[$userid]->is_locked(); $grade->hidden = $grade_grades[$userid]->is_hidden(); $grade->overridden = $grade_grades[$userid]->overridden; $grade->feedback = $grade_grades[$userid]->feedback; $grade->feedbackformat = $grade_grades[$userid]->feedbackformat; $grade->usermodified = $grade_grades[$userid]->usermodified; // create text representation of grade if (in_array($grade_item->id, $needsupdate)) { $grade->grade = false; $grade->str_grade = get_string('error'); } else { if (is_null($grade->grade)) { $grade->str_grade = '-'; } else { $grade->str_grade = grade_format_gradevalue($grade->grade, $grade_item); } } // create html representation of feedback if (is_null($grade->feedback)) { $grade->str_feedback = ''; } else { $grade->str_feedback = format_text($grade->feedback, $grade->feedbackformat); } $item->grades[$userid] = $grade; } } $return->items[$grade_item->itemnumber] = $item; } else { if (!($grade_outcome = grade_outcome::fetch(array('id' => $grade_item->outcomeid)))) { debugging('Incorect outcomeid found'); continue; } // outcome info $outcome = new object(); $outcome->itemnumber = $grade_item->itemnumber; $outcome->scaleid = $grade_outcome->scaleid; $outcome->name = $grade_outcome->get_name(); $outcome->locked = $grade_item->is_locked(); $outcome->hidden = $grade_item->is_hidden(); if (empty($userid_or_ids)) { $userids = array(); } else { if (is_array($userid_or_ids)) { $userids = $userid_or_ids; } else { $userids = array($userid_or_ids); } } if ($userids) { $grade_grades = grade_grade::fetch_users_grades($grade_item, $userids, true); foreach ($userids as $userid) { $grade_grades[$userid]->grade_item =& $grade_item; $grade = new object(); $grade->grade = $grade_grades[$userid]->finalgrade; $grade->locked = $grade_grades[$userid]->is_locked(); $grade->hidden = $grade_grades[$userid]->is_hidden(); $grade->feedback = $grade_grades[$userid]->feedback; $grade->feedbackformat = $grade_grades[$userid]->feedbackformat; $grade->usermodified = $grade_grades[$userid]->usermodified; // create text representation of grade if (in_array($grade_item->id, $needsupdate)) { $grade->grade = false; $grade->str_grade = get_string('error'); } else { if (is_null($grade->grade)) { $grade->grade = 0; $grade->str_grade = get_string('nooutcome', 'grades'); } else { $grade->grade = (int) $grade->grade; $scale = $grade_item->load_scale(); $grade->str_grade = format_string($scale->scale_items[(int) $grade->grade - 1]); } } // create html representation of feedback if (is_null($grade->feedback)) { $grade->str_feedback = ''; } else { $grade->str_feedback = format_text($grade->feedback, $grade->feedbackformat); } $outcome->grades[$userid] = $grade; } } $return->outcomes[$grade_item->itemnumber] = $outcome; } } } // sort results using itemnumbers ksort($return->items, SORT_NUMERIC); ksort($return->outcomes, SORT_NUMERIC); return $return; }
/** * This function will empty a course of user data. * It will retain the activities and the structure of the course. * * @param object $data an object containing all the settings including courseid (without magic quotes) * @return array status array of array component, item, error */ function reset_course_userdata($data) { global $CFG, $USER, $DB; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->libdir . '/completionlib.php'; require_once $CFG->dirroot . '/group/lib.php'; $data->courseid = $data->id; $context = get_context_instance(CONTEXT_COURSE, $data->courseid); // calculate the time shift of dates if (!empty($data->reset_start_date)) { // time part of course startdate should be zero $data->timeshift = $data->reset_start_date - usergetmidnight($data->reset_start_date_old); } else { $data->timeshift = 0; } // result array: component, item, error $status = array(); // start the resetting $componentstr = get_string('general'); // move the course start time if (!empty($data->reset_start_date) and $data->timeshift) { // change course start data $DB->set_field('course', 'startdate', $data->reset_start_date, array('id' => $data->courseid)); // update all course and group events - do not move activity events $updatesql = "UPDATE {event}\n SET timestart = timestart + ?\n WHERE courseid=? AND instance=0"; $DB->execute($updatesql, array($data->timeshift, $data->courseid)); $status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false); } if (!empty($data->reset_logs)) { $DB->delete_records('log', array('course' => $data->courseid)); $status[] = array('component' => $componentstr, 'item' => get_string('deletelogs'), 'error' => false); } if (!empty($data->reset_events)) { $DB->delete_records('event', array('courseid' => $data->courseid)); $status[] = array('component' => $componentstr, 'item' => get_string('deleteevents', 'calendar'), 'error' => false); } if (!empty($data->reset_notes)) { require_once $CFG->dirroot . '/notes/lib.php'; note_delete_all($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deletenotes', 'notes'), 'error' => false); } if (!empty($data->delete_blog_associations)) { require_once $CFG->dirroot . '/blog/lib.php'; blog_remove_associations_for_course($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('deleteblogassociations', 'blog'), 'error' => false); } if (!empty($data->reset_course_completion)) { // Delete course completion information $course = $DB->get_record('course', array('id' => $data->courseid)); $cc = new completion_info($course); $cc->delete_course_completion_data(); $status[] = array('component' => $componentstr, 'item' => get_string('deletecoursecompletiondata', 'completion'), 'error' => false); } $componentstr = get_string('roles'); if (!empty($data->reset_roles_overrides)) { $children = get_child_contexts($context); foreach ($children as $child) { $DB->delete_records('role_capabilities', array('contextid' => $child->id)); } $DB->delete_records('role_capabilities', array('contextid' => $context->id)); //force refresh for logged in users mark_context_dirty($context->path); $status[] = array('component' => $componentstr, 'item' => get_string('deletecourseoverrides', 'role'), 'error' => false); } if (!empty($data->reset_roles_local)) { $children = get_child_contexts($context); foreach ($children as $child) { role_unassign_all(array('contextid' => $child->id)); } //force refresh for logged in users mark_context_dirty($context->path); $status[] = array('component' => $componentstr, 'item' => get_string('deletelocalroles', 'role'), 'error' => false); } // First unenrol users - this cleans some of related user data too, such as forum subscriptions, tracking, etc. $data->unenrolled = array(); if (!empty($data->unenrol_users)) { $plugins = enrol_get_plugins(true); $instances = enrol_get_instances($data->courseid, true); foreach ($instances as $key => $instance) { if (!isset($plugins[$instance->enrol])) { unset($instances[$key]); continue; } if (!$plugins[$instance->enrol]->allow_unenrol($instance)) { unset($instances[$key]); } } $sqlempty = $DB->sql_empty(); foreach ($data->unenrol_users as $withroleid) { $sql = "SELECT DISTINCT ue.userid, ue.enrolid\n FROM {user_enrolments} ue\n JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)\n JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid)\n JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.roleid = :roleid AND ra.userid = ue.userid)"; $params = array('courseid' => $data->courseid, 'roleid' => $withroleid, 'courselevel' => CONTEXT_COURSE); $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $ue) { if (!isset($instances[$ue->enrolid])) { continue; } $plugins[$instances[$ue->enrolid]->enrol]->unenrol_user($instances[$ue->enrolid], $ue->userid); $data->unenrolled[$ue->userid] = $ue->userid; } } } if (!empty($data->unenrolled)) { $status[] = array('component' => $componentstr, 'item' => get_string('unenrol', 'enrol') . ' (' . count($data->unenrolled) . ')', 'error' => false); } $componentstr = get_string('groups'); // remove all group members if (!empty($data->reset_groups_members)) { groups_delete_group_members($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removegroupsmembers', 'group'), 'error' => false); } // remove all groups if (!empty($data->reset_groups_remove)) { groups_delete_groups($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroups', 'group'), 'error' => false); } // remove all grouping members if (!empty($data->reset_groupings_members)) { groups_delete_groupings_groups($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('removegroupingsmembers', 'group'), 'error' => false); } // remove all groupings if (!empty($data->reset_groupings_remove)) { groups_delete_groupings($data->courseid, false); $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroupings', 'group'), 'error' => false); } // Look in every instance of every module for data to delete $unsupported_mods = array(); if ($allmods = $DB->get_records('modules')) { foreach ($allmods as $mod) { $modname = $mod->name; if (!$DB->count_records($modname, array('course' => $data->courseid))) { continue; // skip mods with no instances } $modfile = $CFG->dirroot . '/mod/' . $modname . '/lib.php'; $moddeleteuserdata = $modname . '_reset_userdata'; // Function to delete user data if (file_exists($modfile)) { include_once $modfile; if (function_exists($moddeleteuserdata)) { $modstatus = $moddeleteuserdata($data); if (is_array($modstatus)) { $status = array_merge($status, $modstatus); } else { debugging('Module ' . $modname . ' returned incorrect staus - must be an array!'); } } else { $unsupported_mods[] = $mod; } } else { debugging('Missing lib.php in ' . $modname . ' module!'); } } } // mention unsupported mods if (!empty($unsupported_mods)) { foreach ($unsupported_mods as $mod) { $status[] = array('component' => get_string('modulenameplural', $mod->name), 'item' => '', 'error' => get_string('resetnotimplemented')); } } $componentstr = get_string('gradebook', 'grades'); // reset gradebook if (!empty($data->reset_gradebook_items)) { remove_course_grades($data->courseid, false); grade_grab_course_grades($data->courseid); grade_regrade_final_grades($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removeallcourseitems', 'grades'), 'error' => false); } else { if (!empty($data->reset_gradebook_grades)) { grade_course_reset($data->courseid); $status[] = array('component' => $componentstr, 'item' => get_string('removeallcoursegrades', 'grades'), 'error' => false); } } // reset comments if (!empty($data->reset_comments)) { require_once $CFG->dirroot . '/comment/lib.php'; comment::reset_course_page_comments($context); } return $status; }
/** * put all activity grade items in the correct grade category and mark all for recalculation */ protected function after_execute() { global $DB; $conditions = array('backupid' => $this->get_restoreid(), 'itemname' => 'grade_item'); $rs = $DB->get_recordset('backup_ids_temp', $conditions); // We need this for calculation magic later on. $mappings = array(); if (!empty($rs)) { foreach ($rs as $grade_item_backup) { // Store the oldid with the new id. $mappings[$grade_item_backup->itemid] = $grade_item_backup->newitemid; $updateobj = new stdclass(); $updateobj->id = $grade_item_backup->newitemid; //if this is an activity grade item that needs to be put back in its correct category if (!empty($grade_item_backup->parentitemid)) { $oldcategoryid = $this->get_mappingid('grade_category', $grade_item_backup->parentitemid, null); if (!is_null($oldcategoryid)) { $updateobj->categoryid = $oldcategoryid; $DB->update_record('grade_items', $updateobj); } } else { //mark course and category items as needing to be recalculated $updateobj->needsupdate = 1; $DB->update_record('grade_items', $updateobj); } } } $rs->close(); // We need to update the calculations for calculated grade items that may reference old // grade item ids using ##gi\d+##. // $mappings can be empty, use 0 if so (won't match ever) list($sql, $params) = $DB->get_in_or_equal(array_values($mappings), SQL_PARAMS_NAMED, 'param', true, 0); $sql = "SELECT gi.id, gi.calculation\n FROM {grade_items} gi\n WHERE gi.id {$sql} AND\n calculation IS NOT NULL"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $gradeitem) { // Collect all of the used grade item id references if (preg_match_all('/##gi(\\d+)##/', $gradeitem->calculation, $matches) < 1) { // This calculation doesn't reference any other grade items... EASY! continue; } // For this next bit we are going to do the replacement of id's in two steps: // 1. We will replace all old id references with a special mapping reference. // 2. We will replace all mapping references with id's // Why do we do this? // Because there potentially there will be an overlap of ids within the query and we // we substitute the wrong id.. safest way around this is the two step system $calculationmap = array(); $mapcount = 0; foreach ($matches[1] as $match) { // Check that the old id is known to us, if not it was broken to begin with and will // continue to be broken. if (!array_key_exists($match, $mappings)) { continue; } // Our special mapping key $mapping = '##MAPPING' . $mapcount . '##'; // The old id that exists within the calculation now $oldid = '##gi' . $match . '##'; // The new id that we want to replace the old one with. $newid = '##gi' . $mappings[$match] . '##'; // Replace in the special mapping key $gradeitem->calculation = str_replace($oldid, $mapping, $gradeitem->calculation); // And record the mapping $calculationmap[$mapping] = $newid; $mapcount++; } // Iterate all special mappings for this calculation and replace in the new id's foreach ($calculationmap as $mapping => $newid) { $gradeitem->calculation = str_replace($mapping, $newid, $gradeitem->calculation); } // Update the calculation now that its being remapped $DB->update_record('grade_items', $gradeitem); } $rs->close(); // Need to correct the grade category path and parent $conditions = array('courseid' => $this->get_courseid()); $rs = $DB->get_recordset('grade_categories', $conditions); // Get all the parents correct first as grade_category::build_path() loads category parents from the DB foreach ($rs as $gc) { if (!empty($gc->parent)) { $grade_category = new stdClass(); $grade_category->id = $gc->id; $grade_category->parent = $this->get_mappingid('grade_category', $gc->parent); $DB->update_record('grade_categories', $grade_category); } } $rs->close(); // Now we can rebuild all the paths $rs = $DB->get_recordset('grade_categories', $conditions); foreach ($rs as $gc) { $grade_category = new stdClass(); $grade_category->id = $gc->id; $grade_category->path = grade_category::build_path($gc); $grade_category->depth = substr_count($grade_category->path, '/') - 1; $DB->update_record('grade_categories', $grade_category); } $rs->close(); // Restore marks items as needing update. Update everything now. grade_regrade_final_grades($this->get_courseid()); }
/** * Get the report data * @param stdClass $course course object * @param stdClass $context context object * @param stdClass $user user object (it can be null for all the users) * @param int $userid the user to retrieve data from, 0 for all * @param int $groupid the group id to filter * @param bool $tabledata whether to get the table data (true) or the gradeitemdata * @return array data and possible warnings * @since Moodle 3.2 */ protected static function get_report_data($course, $context, $user, $userid, $groupid, $tabledata = true) { global $CFG; $warnings = array(); // Require files here to save some memory in case validation fails. require_once $CFG->dirroot . '/group/lib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/grade/lib.php'; require_once $CFG->dirroot . '/grade/report/user/lib.php'; // Force regrade to update items marked as 'needupdate'. grade_regrade_final_grades($course->id); $gpr = new grade_plugin_return(array('type' => 'report', 'plugin' => 'user', 'courseid' => $course->id, 'userid' => $userid)); $reportdata = array(); // Just one user. if ($user) { $report = new grade_report_user($course->id, $gpr, $context, $userid); $report->fill_table(); $gradeuserdata = array('courseid' => $course->id, 'userid' => $user->id, 'userfullname' => fullname($user), 'maxdepth' => $report->maxdepth); if ($tabledata) { $gradeuserdata['tabledata'] = $report->tabledata; } else { $gradeuserdata['gradeitems'] = $report->gradeitemsdata; } $reportdata[] = $gradeuserdata; } else { $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol); $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol); $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $context); $gui = new graded_users_iterator($course, null, $groupid); $gui->require_active_enrolment($showonlyactiveenrol); $gui->init(); while ($userdata = $gui->next_user()) { $currentuser = $userdata->user; $report = new grade_report_user($course->id, $gpr, $context, $currentuser->id); $report->fill_table(); $gradeuserdata = array('courseid' => $course->id, 'userid' => $currentuser->id, 'userfullname' => fullname($currentuser), 'maxdepth' => $report->maxdepth); if ($tabledata) { $gradeuserdata['tabledata'] = $report->tabledata; } else { $gradeuserdata['gradeitems'] = $report->gradeitemsdata; } $reportdata[] = $gradeuserdata; } $gui->close(); } return array($reportdata, $warnings); }
} $grade_item->update(); $recreatetree = true; // Grade item checkbox inputs. } elseif (preg_match('/^(weightoverride)_([0-9]+)$/', $key, $matches)) { $param = $matches[1]; $aid = $matches[2]; $value = clean_param($value, PARAM_BOOL); $grade_item = grade_item::fetch(array('id' => $aid, 'courseid' => $courseid)); $grade_item->{$param} = $value; $grade_item->update(); $recreatetree = true; } } $originalweights = grade_helper::fetch_all_natural_weights_for_course($courseid); grade_regrade_final_grades($courseid); $alteredweights = grade_helper::fetch_all_natural_weights_for_course($courseid); if (array_diff($originalweights, $alteredweights)) { $normalisationmessage = get_string('weightsadjusted', 'grades'); } } print_grade_page_head($courseid, 'settings', 'setup', get_string('categoriesanditems', 'grades')); // Print Table of categories and items echo $OUTPUT->box_start('gradetreebox generalbox'); echo '<form id="gradetreeform" method="post" action="' . $returnurl . '">'; echo '<div>'; echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />'; //did we update something in the db and thus invalidate $grade_edit_tree? if ($recreatetree) { $grade_edit_tree = new grade_edit_tree($gtree, $movingeid, $gpr); }
/** * Use the grade min and max from the grade_item. * * This is reserved for core use after an upgrade. * * @param int $courseid The current course id. */ function grade_upgrade_use_min_max_from_grade_item($courseid) { grade_set_setting($courseid, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM); grade_force_full_regrading($courseid); // Do this now, because it probably happened to late in the page load to be happen automatically. grade_regrade_final_grades($courseid); }