From 13ba90363484ae8f1abed0fab115909130be71f2 Mon Sep 17 00:00:00 2001 From: "Andrew Davis (andyjdavis)" Date: Fri, 8 Apr 2011 15:06:27 +0800 Subject: [PATCH] enrol MDL-25718 added ability to recover user grades from grade history --- enrol/ajax.php | 6 ++ enrol/locallib.php | 2 + enrol/renderer.php | 7 +- enrol/users.php | 5 +- .../yui/enrolmentmanager/enrolmentmanager.js | 16 +++- lang/en/enrol.php | 1 + lib/gradelib.php | 84 +++++++++++++++++-- 7 files changed, 109 insertions(+), 12 deletions(-) diff --git a/enrol/ajax.php b/enrol/ajax.php index 44db51577af..1f7cbef7b1a 100644 --- a/enrol/ajax.php +++ b/enrol/ajax.php @@ -154,6 +154,8 @@ switch ($action) { $roleid = optional_param('role', null, PARAM_INT); $duration = optional_param('duration', 0, PARAM_INT); $startdate = optional_param('startdate', 0, PARAM_INT); + $recovergrades = optional_param('recovergrades', 0, PARAM_INT); + if (empty($roleid)) { $roleid = null; } @@ -185,6 +187,10 @@ switch ($action) { $plugin = $plugins[$instance->enrol]; if ($plugin->allow_enrol($instance) && has_capability('enrol/'.$plugin->get_name().':enrol', $context)) { $plugin->enrol_user($instance, $user->id, $roleid, $timestart, $timeend); + if ($recovergrades) { + require_once($CFG->libdir.'/gradelib.php'); + grade_recover_history_grades($user->id, $instance->courseid); + } } else { throw new enrol_ajax_exception('enrolnotpermitted'); } diff --git a/enrol/locallib.php b/enrol/locallib.php index dcf4bb728ba..448e6bc5d76 100644 --- a/enrol/locallib.php +++ b/enrol/locallib.php @@ -613,6 +613,8 @@ class course_enrolment_manager { * @return bool */ public function edit_enrolment($userenrolment, $data) { + //Only allow editing if the user has the appropriate capability + //Already checked in /enrol/users.php but checking again in case this function is called from elsewhere list($instance, $plugin) = $this->get_user_enrolment_components($userenrolment); if ($instance && $plugin && $plugin->allow_manage($instance) && has_capability("enrol/$instance->enrol:manage", $this->context)) { if (!isset($data->status)) { diff --git a/enrol/renderer.php b/enrol/renderer.php index 6e30ee118c0..61ad0241548 100644 --- a/enrol/renderer.php +++ b/enrol/renderer.php @@ -626,6 +626,7 @@ class course_enrolment_users_table extends course_enrolment_table { * @return single_button|url_select */ public function get_enrolment_selector() { + global $CFG; static $count = 0; $instances = $this->manager->get_enrolment_instances(); @@ -686,7 +687,8 @@ class course_enrolment_users_table extends course_enrolment_table { 'startdatetoday', 'durationdays', 'enrolperiod', - 'finishenrollingusers'), 'enrol'); + 'finishenrollingusers', + 'recovergrades'), 'enrol'); $this->moodlepage->requires->string_for_js('assignroles', 'role'); $this->moodlepage->requires->string_for_js('startingfrom', 'moodle'); @@ -698,7 +700,8 @@ class course_enrolment_users_table extends course_enrolment_table { 'ajaxurl'=>'/enrol/ajax.php', 'url'=>$this->moodlepage->url->out(false), 'optionsStartDate'=>$startdateoptions, - 'defaultRole'=>$instance->roleid); + 'defaultRole'=>$instance->roleid, + 'disableGradeHistory'=>$CFG->disablegradehistory); $this->moodlepage->requires->yui_module($modules, $function, array($arguments)); } return $control; diff --git a/enrol/users.php b/enrol/users.php index f206e5cc90f..3264ceba9ff 100644 --- a/enrol/users.php +++ b/enrol/users.php @@ -62,7 +62,7 @@ if ($action) { switch ($action) { /** - * Unenrols a user from this course + * Unenrols a user from this course (includes removing all of their grades) */ case 'unenrol': $ue = $DB->get_record('user_enrolments', array('id'=>required_param('ue', PARAM_INT)), '*', MUST_EXIST); @@ -73,6 +73,7 @@ if ($action) { } else { $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST); $yesurl = new moodle_url($PAGE->url, array('action'=>'unenrol', 'ue'=>$ue->id, 'confirm'=>1, 'sesskey'=>sesskey())); + $message = get_string('unenrolconfirm', 'enrol', array('user'=>fullname($user, true), 'course'=>format_string($course->fullname))); $pagetitle = get_string('unenrol', 'enrol'); $pagecontent = $OUTPUT->confirm($message, $yesurl, $PAGE->url); @@ -166,6 +167,8 @@ if ($action) { */ case 'edit': $ue = $DB->get_record('user_enrolments', array('id'=>required_param('ue', PARAM_INT)), '*', MUST_EXIST); + + //Only show the edit form if the user has the appropriate capability list($instance, $plugin) = $manager->get_user_enrolment_components($ue); if ($instance && $plugin && $plugin->allow_manage($instance) && has_capability("enrol/$instance->enrol:manage", $manager->get_context())) { $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST); diff --git a/enrol/yui/enrolmentmanager/enrolmentmanager.js b/enrol/yui/enrolmentmanager/enrolmentmanager.js index 864cd913222..c0b67efa0e0 100644 --- a/enrol/yui/enrolmentmanager/enrolmentmanager.js +++ b/enrol/yui/enrolmentmanager/enrolmentmanager.js @@ -20,7 +20,8 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) { DEFAULTROLE : 'defaultRole', DEFAULTSTARTDATE : 'defaultStartDate', DEFAULTDURATION : 'defaultDuration', - ASSIGNABLEROLES : 'assignableRoles' + ASSIGNABLEROLES : 'assignableRoles', + DISABLEGRADEHISTORY : 'disableGradeHistory' }; /** CSS classes for nodes in structure **/ var CSS = { @@ -48,6 +49,8 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) { ODD : 'odd', EVEN : 'even', HIDDEN : 'hidden', + RECOVERGRADESCHECK : 'uep-recovergradescheck', + RECOVERGRADESCHECKTITLE : 'uep-recovergradeschecktitle', SEARCHOPTIONS : 'uep-searchoptions', COLLAPSIBLEHEADING : 'collapsibleheading', COLLAPSIBLEAREA : 'collapsiblearea', @@ -70,6 +73,11 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) { _loadingNode : null, _escCloseEvent : null, initializer : function(config) { + recovergradescheckbox = null; + if (this.get(UEP.DISABLEGRADEHISTORY) != true) { + recovergradescheckbox = Y.Node.create('
'); + } + this.set(UEP.BASE, Y.Node.create('
') .append(Y.Node.create('
') .append(Y.Node.create('
') @@ -80,6 +88,7 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) { .append(Y.Node.create('
'+M.str.role.assignroles+'
') .append(Y.Node.create('')) ) + .append(recovergradescheckbox) .append(Y.Node.create('
') .append(Y.Node.create('
'+M.str.enrol.enrolmentoptions+'
')) .append(Y.Node.create('
') @@ -367,6 +376,8 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) { params['role'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.ROLE+' select').get('value'); params['startdate'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.STARTDATE+' select').get('value'); params['duration'] = this.get(UEP.BASE).one('.'+CSS.SEARCHOPTION+'.'+CSS.DURATION+' select').get('value'); + params['recovergrades'] = this.get(UEP.BASE).one('#recovergrades').get('checked')?1:0; + Y.io(M.cfg.wwwroot+this.get(UEP.AJAXURL), { method:'POST', data:build_querystring(params), @@ -487,6 +498,9 @@ YUI.add('moodle-enrol-enrolmentmanager', function(Y) { }, optionsStartDate : { value : [] + }, + disableGradeHistory : { + value : 0 } } }); diff --git a/lang/en/enrol.php b/lang/en/enrol.php index 5abd0cbe1ef..4222372591f 100644 --- a/lang/en/enrol.php +++ b/lang/en/enrol.php @@ -77,6 +77,7 @@ $string['participationsuspended'] = 'Suspended'; $string['periodend'] = 'until {$a}'; $string['periodstart'] = 'from {$a}'; $string['periodstartend'] = 'from {$a->start} until {$a->end}'; +$string['recovergrades'] = 'Recover user\'s old grades if possible'; $string['rolefromthiscourse'] = '{$a->role} (Assigned in this course)'; $string['rolefrommetacourse'] = '{$a->role} (Inherited from parent course)'; $string['rolefromcategory'] = '{$a->role} (Inherited from course category)'; diff --git a/lib/gradelib.php b/lib/gradelib.php index 1fd916fa591..9b0959a3883 100644 --- a/lib/gradelib.php +++ b/lib/gradelib.php @@ -913,6 +913,76 @@ function grade_force_site_regrading() { $DB->set_field('grade_items', 'needsupdate', 1); } +/** + * Recover a user's grades from grade_grades_history + * @param int $userid the user ID whose grades we want to recover + * @param int $courseid the relevant course + * @return bool true if successful or false if there was an error or no grades could be recovered + */ +function grade_recover_history_grades($userid, $courseid) { + global $CFG, $DB; + + if ($CFG->disablegradehistory) { + debugging('Attempting to recover grades when grade history is disabled.'); + return false; + } + + //Were grades recovered? Flag to return. + $recoveredgrades = false; + + //Check the user is enrolled in this course + //Dont bother checking if they have a gradeable role. They may get one later so recover + //whatever grades they have now just in case. + $course_context = get_context_instance(CONTEXT_COURSE, $courseid); + if (!is_enrolled($course_context, $userid)) { + debugging('Attempting to recover the grades of a user who is deleted or not enrolled. Skipping recover.'); + return false; + } + + //Check for existing grades for this user in this course + //Recovering grades when the user already has grades can lead to duplicate indexes and bad data + //In the future we could move the existing grades to the history table then recover the grades from before then + $sql = "SELECT gg.id FROM {grade_grades} gg + JOIN {grade_items} gi ON gi.id = gg.itemid + WHERE gi.courseid = :courseid AND gg.userid = :userid"; + $params = array('userid' => $userid, 'courseid' => $courseid); + if ($DB->record_exists_sql($sql, $params)) { + debugging('Attempting to recover the grades of a user who already has grades. Skipping recover.'); + return false; + } else { + //Retrieve the user's old grades + //have history ID as first column to guarantee we a unique first column + $sql = "SELECT h.id, gi.itemtype, gi.itemmodule, gi.iteminstance as iteminstance, gi.itemnumber, h.source, h.itemid, h.userid, h.rawgrade, h.rawgrademax, h.rawgrademin, h.rawscaleid, h.usermodified, h.finalgrade, h.hidden, h.locked, h.locktime, h.exported, h.overridden, h.excluded, h.feedback, h.feedbackformat, h.information, h.informationformat, h.timemodified, itemcreated.tm AS timecreated + FROM {grade_grades_history} h + JOIN (SELECT itemid, MAX(id) AS id FROM {grade_grades_history} + WHERE userid = :userid1 GROUP BY itemid) maxquery ON h.id = maxquery.id AND h.itemid = maxquery.itemid + JOIN {grade_items} gi ON gi.id = h.itemid + JOIN (SELECT itemid, MAX(timemodified) AS tm FROM {grade_grades_history} WHERE userid = :userid2 AND action = :insertaction GROUP BY itemid) itemcreated ON itemcreated.itemid = h.itemid + WHERE gi.courseid = :courseid"; + $params = array('userid1' => $userid, 'userid2' => $userid , 'insertaction' => GRADE_HISTORY_INSERT, 'courseid' => $courseid); + $oldgrades = $DB->get_records_sql($sql, $params); + + //now move the old grades to the grade_grades table + foreach ($oldgrades as $oldgrade) { + unset($oldgrade->id); + + $grade = new grade_grade($oldgrade, false);//2nd arg false as dont want to try and retrieve a record from the DB + $grade->insert($oldgrade->source); + + //dont include default empty grades created when activities are created + if (!empty($oldgrade->finalgrade) || !empty($oldgrade->feedback)) { + $recoveredgrades = true; + } + } + } + + //Some activities require manual grade synching (moving grades from the activity into the gradebook) + //If the student was deleted when synching was done they may have grades in the activity that haven't been moved across + grade_grab_course_grades($courseid, null, $userid); + + return $recoveredgrades; +} + /** * Updates all final grades in course. * @@ -1032,14 +1102,12 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null) /** * Refetches data from all course activities - * - * @global object - * @global object - * @param int $courseid - * @param string $modname + * @param int $courseid the course ID + * @param string $modname limit the grade fetch to a single module type + * @param int $userid limit the grade fetch to a single user * @return void */ -function grade_grab_course_grades($courseid, $modname=null) { +function grade_grab_course_grades($courseid, $modname=null, $userid=0) { global $CFG, $DB; if ($modname) { @@ -1050,7 +1118,7 @@ function grade_grab_course_grades($courseid, $modname=null) { if ($modinstances = $DB->get_records_sql($sql, $params)) { foreach ($modinstances as $modinstance) { - grade_update_mod_grades($modinstance); + grade_update_mod_grades($modinstance, $userid); } } return; @@ -1075,7 +1143,7 @@ function grade_grab_course_grades($courseid, $modname=null) { if ($modinstances = $DB->get_records_sql($sql, $params)) { foreach ($modinstances as $modinstance) { - grade_update_mod_grades($modinstance); + grade_update_mod_grades($modinstance, $userid); } } }