/** * Tests update score without sending item details. * Grade item should not be created without item name. * * @return void */ public function test_update_score() { global $DB; $this->set_user('admin'); $this->assertEquals(0, $DB->count_records('grade_items')); // Add an mhaairs item directly. $iteminstance = 24993; $itemparams = array('courseid' => $this->course->id, 'itemtype' => 'manual', 'itemmodule' => 'mhaairs', 'iteminstance' => $iteminstance, 'itemname' => 'MH Assignment'); $gitem = new \grade_item($itemparams, false); $gitem->insert('mhaairs'); $this->assertEquals(2, $DB->count_records('grade_items')); $service = 'block_mhaairs_gradebookservice_external::update_grade'; $grades = array('userid' => 'student1', 'rawgrade' => 93); $gradesjson = urlencode(json_encode($grades)); $servicedata = array(); $servicedata['source'] = 'mhaairs'; $servicedata['courseid'] = 'tc1'; $servicedata['itemtype'] = 'manual'; $servicedata['itemmodule'] = 'mhaairs'; $servicedata['iteminstance'] = 111; $servicedata['itemnumber'] = 0; $servicedata['grades'] = $gradesjson; $servicedata['itemdetails'] = null; // Send score via service without details, item by instance doesn't exist. $result = call_user_func_array($service, $servicedata); $this->assertEquals(GRADE_UPDATE_FAILED, $result); $this->assertEquals(2, $DB->count_records('grade_items')); // Set the existing item instance. $servicedata['iteminstance'] = $iteminstance; // Send score via service without details, item by instance exists. $result = call_user_func_array($service, $servicedata); $this->assertEquals(GRADE_UPDATE_OK, $result); $this->assertEquals(2, $DB->count_records('grade_items')); $this->assertEquals(1, $DB->count_records('grade_grades')); $usergrade = $DB->get_field('grade_grades', 'finalgrade', array('userid' => $this->student1->id)); $this->assertEquals(93, $usergrade); // Set typical item details for score update. $itemdetails = array('courseid' => '3', 'idnumber' => '111', 'identity_type' => null, 'needsupdate' => 1, 'useexisting' => 0); $itemdetailsjson = urlencode(json_encode($grades)); $servicedata['itemdetails'] = $itemdetailsjson; $grades = array('userid' => 'student1', 'rawgrade' => 94); $gradesjson = urlencode(json_encode($grades)); $servicedata['grades'] = $gradesjson; // Send score via service to item with details. $result = call_user_func_array($service, $servicedata); $this->assertEquals(GRADE_UPDATE_OK, $result); $this->assertEquals(2, $DB->count_records('grade_items')); $this->assertEquals(1, $DB->count_records('grade_grades')); $usergrade = $DB->get_field('grade_grades', 'finalgrade', array('userid' => $this->student1->id)); $this->assertEquals(94, $usergrade); }
/** * Tests the gradebookservice get grade service. * * @return void */ public function test_get_grade() { global $DB; $callback = 'block_mhaairs_gradebookservice_external::get_grade'; $this->set_user('admin'); // Add mhaairs grade item directly. $params = array('courseid' => $this->course->id, 'itemtype' => 'manual', 'itemmodule' => 'mhaairs', 'iteminstance' => 101, 'itemname' => 'MH Assignment'); $gitem = new \grade_item($params, false); $gitem->insert('mhaairs'); // Add user grade directly. $params = array('itemid' => $gitem->id, 'userid' => $this->student1->id, 'finalgrade' => '95'); $ggrade = new \grade_grade($params, false); $ggrade->insert('mhaairs'); // Service params. $serviceparams = array('source' => 'mhaairs', 'courseid' => $this->course->id, 'itemtype' => 'manual', 'itemmodule' => 'mhaairs', 'iteminstance' => 101, 'itemnumber' => 0, 'grades' => null, 'itemdetails' => null); // Grade details. $grades = array('userid' => 'student1', 'identity_type' => ''); $gradesjson = urlencode(json_encode($grades)); $serviceparams['grades'] = $gradesjson; $result = call_user_func_array($callback, $serviceparams); $this->assertEquals('MH Assignment', $result['item']['itemname']); $this->assertEquals($this->student1->id, $result['grades'][0]['userid']); $this->assertEquals(95, $result['grades'][0]['grade']); }
/** * Create a grade_item. * * @param array|stdClass $record * @return stdClass the grade item record */ public function create_grade_item($record = null) { global $CFG; require_once "{$CFG->libdir}/gradelib.php"; $this->gradeitemcounter++; if (!isset($record['itemtype'])) { $record['itemtype'] = 'manual'; } if (!isset($record['itemname'])) { $record['itemname'] = 'Grade item ' . $this->gradeitemcounter; } if (isset($record['outcomeid'])) { $outcome = new grade_outcome(array('id' => $record['outcomeid'])); $record['scaleid'] = $outcome->scaleid; } if (isset($record['scaleid'])) { $record['gradetype'] = GRADE_TYPE_SCALE; } else { if (!isset($record['gradetype'])) { $record['gradetype'] = GRADE_TYPE_VALUE; } } // Create new grade item in this course. $gradeitem = new grade_item($record, false); $gradeitem->insert(); $gradeitem->update_from_db(); return $gradeitem->get_record_data(); }
/** * Test sync_completionelements method. * * @dataProvider dataprovider_sync_completionelements * @param array $gradeitem Array of parameters to create grade_item. * @param array $gradegrade Array of parameters to create grade_grade. * @param array $coursecompletion Array of parameters to create coursecompletion. * @param array $studentgrade Array of parameters to create student_grade. * @param int $timenow Current timestamp to enable testing with time. * @param array $expectedstudentgrade Array of parameters we expect to be set in the student_grade. */ public function test_sync_completionelements($gradeitem, $gradegrade, $coursecompletion, $studentgrade, $timenow, $expectedstudentgrade) { global $DB; $sync = new \local_elisprogram\moodle\synchronize(); // Test data setup. $crs = new \course(array('idnumber' => 'CRS1', 'name' => 'Course 1', 'syllabus' => '')); $crs->save(); $cls = new \pmclass(array('courseid' => $crs->id, 'idnumber' => 'CLS1')); $cls->save(); $usr = new \user(array('username' => 'test1', 'idnumber' => 'test2', 'firstname' => 'test', 'lastname' => 'user', 'email' => '*****@*****.**', 'country' => 'CA')); $usr->save(); $musr = $this->getDataGenerator()->create_user(); $gradeitem = new \grade_item($gradeitem, false); $gradeitem->insert(); $gradegrade['itemid'] = $gradeitem->id; $gradegrade['userid'] = $musr->id; $gradegrade = new \grade_grade($gradegrade, false); $gradegrade->insert(); $coursecompletion['courseid'] = $crs->id; $coursecompletion = new \coursecompletion($coursecompletion); $coursecompletion->save(); if ($studentgrade !== false) { $studentgrade['classid'] = $cls->id; $studentgrade['userid'] = $usr->id; $studentgrade['completionid'] = $coursecompletion->id; $studentgrade = new \student_grade($studentgrade); $studentgrade->save(); $studentgrade = new \student_grade($studentgrade->id); $studentgrade->load(); } // Method parameter setup. $causer = (object) array('cmid' => $usr->id, 'pmclassid' => $cls->id); $gis = array($gradeitem->id => (object) array('id' => $gradeitem->id, 'grademax' => $gradeitem->grademax)); $compelements = array($gradeitem->id => (object) array('id' => $coursecompletion->id, 'completion_grade' => $coursecompletion->completion_grade)); $moodlegrades = array($gradeitem->id => $gradegrade); if ($studentgrade !== false) { $cmgrades = array($coursecompletion->id => $studentgrade->to_object()); } else { $cmgrades = array(); } $sync->sync_completionelements($causer, $gis, $compelements, $moodlegrades, $cmgrades, $timenow); $actualstudentgrade = false; if ($studentgrade !== false) { $actualstudentgrade = $DB->get_record(\student_grade::TABLE, array('id' => $studentgrade->id)); } else { $actualstudentgrades = $DB->get_records(\student_grade::TABLE, array(), 'id DESC'); if (!empty($actualstudentgrades)) { $actualstudentgrade = array_shift($actualstudentgrades); } } if ($actualstudentgrade !== false) { if ($expectedstudentgrade !== false) { $expectedstudentgrade['id'] = $actualstudentgrade->id; $expectedstudentgrade['classid'] = $cls->id; $expectedstudentgrade['userid'] = $usr->id; $expectedstudentgrade['completionid'] = $coursecompletion->id; // This is here for tests where we can't reliably predetermine timemodified (i.e. no-sync cases). if (!isset($expectedstudentgrade['timemodified'])) { $expectedstudentgrade['timemodified'] = $actualstudentgrade->timemodified; } $expectedstudentgrade = (object) $expectedstudentgrade; $this->assertEquals($expectedstudentgrade, $actualstudentgrade); } else { $this->assertTrue(false, 'A student_grade was created when one was not expected.'); } } else { // If $expectedstudentgrade is false we were expected no grade to be created. If not, we have a problem. if ($expectedstudentgrade !== false) { $this->assertTrue(false, 'No student_grade created when one was expected'); } else { $this->assertTrue(true); } } }
/** * Retrieves this grade categories' associated grade_item from the database * * If no grade_item exists yet, creates one. * * @return grade_item */ public function get_grade_item() { if (empty($this->id)) { debugging("Attempt to obtain a grade_category's associated grade_item without the category's ID being set."); return false; } if (empty($this->parent)) { $params = array('courseid' => $this->courseid, 'itemtype' => 'course', 'iteminstance' => $this->id); } else { $params = array('courseid' => $this->courseid, 'itemtype' => 'category', 'iteminstance' => $this->id); } if (!($grade_items = grade_item::fetch_all($params))) { // create a new one $grade_item = new grade_item($params, false); $grade_item->gradetype = GRADE_TYPE_VALUE; $grade_item->insert('system'); } else { if (count($grade_items) == 1) { // found existing one $grade_item = reset($grade_items); } else { debugging("Found more than one grade_item attached to category id:" . $this->id); // return first one $grade_item = reset($grade_items); } } return $grade_item; }
/** * Validate that the version 1 plugin deletes appropriate associations when * deleting a user */ public function test_version1importdeleteuserdeletesassociations() { global $CFG, $DB; set_config('siteadmins', 0); // New config settings needed for course format refactoring in 2.4. set_config('numsections', 15, 'moodlecourse'); set_config('hiddensections', 0, 'moodlecourse'); set_config('coursedisplay', 1, 'moodlecourse'); require_once $CFG->dirroot . '/cohort/lib.php'; require_once $CFG->dirroot . '/course/lib.php'; require_once $CFG->dirroot . '/group/lib.php'; require_once $CFG->dirroot . '/lib/enrollib.php'; require_once $CFG->dirroot . '/lib/gradelib.php'; // Create our test user, and determine their userid. $this->run_core_user_import(array()); $userid = (int) $DB->get_field('user', 'id', array('username' => 'rlipusername', 'mnethostid' => $CFG->mnet_localhost_id)); // Create cohort. $cohort = new stdClass(); $cohort->name = 'testcohort'; $cohort->contextid = context_system::instance()->id; $cohortid = cohort_add_cohort($cohort); // Add the user to the cohort. cohort_add_member($cohortid, $userid); // Create a course category - there is no API for doing this. $category = new stdClass(); $category->name = 'testcategory'; $category->id = $DB->insert_record('course_categories', $category); // Create a course. set_config('defaultenrol', 1, 'enrol_manual'); set_config('status', ENROL_INSTANCE_ENABLED, 'enrol_manual'); $course = new stdClass(); $course->category = $category->id; $course->fullname = 'testfullname'; $course = create_course($course); // Create a grade. $gradeitem = new grade_item(array('courseid' => $course->id, 'itemtype' => 'manual', 'itemname' => 'testitem'), false); $gradeitem->insert(); $gradegrade = new grade_grade(array('itemid' => $gradeitem->id, 'userid' => $userid), false); $gradegrade->insert(); // Send the user an unprocessed message. set_config('noemailever', true); // Set up a user tag. tag_set('user', $userid, array('testtag')); // Create a new course-level role. $roleid = create_role('testrole', 'testrole', 'testrole'); set_role_contextlevels($roleid, array(CONTEXT_COURSE)); // Enrol the user in the course with the new role. enrol_try_internal_enrol($course->id, $userid, $roleid); // Create a group. $group = new stdClass(); $group->name = 'testgroup'; $group->courseid = $course->id; $groupid = groups_create_group($group); // Add the user to the group. groups_add_member($groupid, $userid); set_user_preference('testname', 'testvalue', $userid); // Create profile field data - don't both with the API here because it's a bit unwieldy. $userinfodata = new stdClass(); $userinfodata->fieldid = 1; $userinfodata->data = 'bogus'; $userinfodata->userid = $userid; $DB->insert_record('user_info_data', $userinfodata); // There is no easily accessible API for doing this. $lastaccess = new stdClass(); $lastaccess->userid = $userid; $lastaccess->courseid = $course->id; $DB->insert_record('user_lastaccess', $lastaccess); $data = array('action' => 'delete', 'username' => 'rlipusername'); $this->run_core_user_import($data, false); // Assert data condition after delete. $this->assertEquals($DB->count_records('message_read', array('useridto' => $userid)), 0); $this->assertEquals($DB->count_records('grade_grades'), 0); $this->assertEquals($DB->count_records('tag_instance'), 0); $this->assertEquals($DB->count_records('cohort_members'), 0); $this->assertEquals($DB->count_records('user_enrolments'), 0); $this->assertEquals($DB->count_records('role_assignments'), 0); $this->assertEquals($DB->count_records('groups_members'), 0); $this->assertEquals($DB->count_records('user_preferences'), 0); $this->assertEquals($DB->count_records('user_info_data'), 0); $this->assertEquals($DB->count_records('user_lastaccess'), 0); }
/** * This function creates all the gradebook data from xml */ function restore_create_gradebook($restore, $xml_file) { global $CFG; $status = true; //Check it exists if (!file_exists($xml_file)) { return false; } // Get info from xml // info will contain the number of record to process $info = restore_read_xml_gradebook($restore, $xml_file); // If we have info, then process if (empty($info)) { return $status; } if (empty($CFG->disablegradehistory) and isset($info->gradebook_histories) and $info->gradebook_histories == "true") { $restore_histories = true; } else { $restore_histories = false; } // make sure top course category exists $course_category = grade_category::fetch_course_category($restore->course_id); $course_category->load_grade_item(); // we need to know if all grade items that were backed up are being restored // if that is not the case, we do not restore grade categories nor gradeitems of category type or course type // i.e. the aggregated grades of that category $restoreall = true; // set to false if any grade_item is not selected/restored or already exist $importing = !empty($SESSION->restore->importing); if ($importing) { $restoreall = false; } else { $prev_grade_items = grade_item::fetch_all(array('courseid' => $restore->course_id)); $prev_grade_cats = grade_category::fetch_all(array('courseid' => $restore->course_id)); // if any categories already present, skip restore of categories from backup - course item or category already exist if (count($prev_grade_items) > 1 or count($prev_grade_cats) > 1) { $restoreall = false; } unset($prev_grade_items); unset($prev_grade_cats); if ($restoreall) { if ($recs = get_records_select("backup_ids", "table_name = 'grade_items' AND backup_code = {$restore->backup_unique_code}", "", "old_id")) { foreach ($recs as $rec) { if ($data = backup_getid($restore->backup_unique_code, 'grade_items', $rec->old_id)) { $info = $data->info; // do not restore if this grade_item is a mod, and $itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#']); if ($itemtype == 'mod') { $olditeminstance = backup_todb($info['GRADE_ITEM']['#']['ITEMINSTANCE']['0']['#']); $itemmodule = backup_todb($info['GRADE_ITEM']['#']['ITEMMODULE']['0']['#']); if (empty($restore->mods[$itemmodule]->granular)) { continue; } else { if (!empty($restore->mods[$itemmodule]->instances[$olditeminstance]->restore)) { continue; } } // at least one activity should not be restored - do not restore categories and manual items at all $restoreall = false; break; } } } } } } // Start ul if (!defined('RESTORE_SILENTLY')) { echo '<ul>'; } // array of restored categories - speedup ;-) $cached_categories = array(); $outcomes = array(); /// Process letters $context = get_context_instance(CONTEXT_COURSE, $restore->course_id); // respect current grade letters if defined if ($status and $restoreall and !record_exists('grade_letters', 'contextid', $context->id)) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeletters', 'grades') . '</li>'; } // Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_letters' AND backup_code = {$restore->backup_unique_code}", "", "old_id"); if ($recs) { foreach ($recs as $rec) { // Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_letters', $rec->old_id); if ($data) { $info = $data->info; $dbrec = new object(); $dbrec->contextid = $context->id; $dbrec->lowerboundary = backup_todb($info['GRADE_LETTER']['#']['LOWERBOUNDARY']['0']['#']); $dbrec->letter = backup_todb($info['GRADE_LETTER']['#']['LETTER']['0']['#']); insert_record('grade_letters', $dbrec); } } } } /// Preprocess outcomes - do not store them yet! if ($status and !$importing and $restoreall) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeoutcomes', 'grades') . '</li>'; } $recs = get_records_select("backup_ids", "table_name = 'grade_outcomes' AND backup_code = '{$restore->backup_unique_code}'", "", "old_id"); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_outcomes', $rec->old_id); if ($data) { $info = $data->info; //first find out if outcome already exists $shortname = backup_todb($info['GRADE_OUTCOME']['#']['SHORTNAME']['0']['#']); if ($candidates = get_records_sql("SELECT *\n FROM {$CFG->prefix}grade_outcomes\n WHERE (courseid IS NULL OR courseid = {$restore->course_id})\n AND shortname = '{$shortname}'\n ORDER BY courseid ASC, id ASC")) { $grade_outcome = reset($candidates); $outcomes[$rec->old_id] = $grade_outcome; continue; } $dbrec = new object(); if (has_capability('moodle/grade:manageoutcomes', get_context_instance(CONTEXT_SYSTEM))) { $oldoutcome = backup_todb($info['GRADE_OUTCOME']['#']['COURSEID']['0']['#']); if (empty($oldoutcome)) { //site wide $dbrec->courseid = null; } else { //course only $dbrec->courseid = $restore->course_id; } } else { // no permission to add site outcomes $dbrec->courseid = $restore->course_id; } //Get the fields $dbrec->shortname = backup_todb($info['GRADE_OUTCOME']['#']['SHORTNAME']['0']['#'], false); $dbrec->fullname = backup_todb($info['GRADE_OUTCOME']['#']['FULLNAME']['0']['#'], false); $dbrec->scaleid = backup_todb($info['GRADE_OUTCOME']['#']['SCALEID']['0']['#'], false); $dbrec->description = backup_todb($info['GRADE_OUTCOME']['#']['DESCRIPTION']['0']['#'], false); $dbrec->timecreated = backup_todb($info['GRADE_OUTCOME']['#']['TIMECREATED']['0']['#'], false); $dbrec->timemodified = backup_todb($info['GRADE_OUTCOME']['#']['TIMEMODIFIED']['0']['#'], false); $dbrec->usermodified = backup_todb($info['GRADE_OUTCOME']['#']['USERMODIFIED']['0']['#'], false); //Need to recode the scaleid if ($scale = backup_getid($restore->backup_unique_code, 'scale', $dbrec->scaleid)) { $dbrec->scaleid = $scale->new_id; } //Need to recode the usermodified if ($modifier = backup_getid($restore->backup_unique_code, 'user', $dbrec->usermodified)) { $dbrec->usermodified = $modifier->new_id; } $grade_outcome = new grade_outcome($dbrec, false); $outcomes[$rec->old_id] = $grade_outcome; } } } } /// Process grade items and grades if ($status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeitems', 'grades') . '</li>'; } $counter = 0; //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_items' AND backup_code = '{$restore->backup_unique_code}'", "id", "old_id"); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_items', $rec->old_id); if ($data) { $info = $data->info; // first find out if category or normal item $itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#'], false); if ($itemtype == 'course' or $itemtype == 'category') { if (!$restoreall or $importing) { continue; } $oldcat = backup_todb($info['GRADE_ITEM']['#']['ITEMINSTANCE']['0']['#'], false); if (!($cdata = backup_getid($restore->backup_unique_code, 'grade_categories', $oldcat))) { continue; } $cinfo = $cdata->info; unset($cdata); if ($itemtype == 'course') { $course_category->fullname = backup_todb($cinfo['GRADE_CATEGORY']['#']['FULLNAME']['0']['#'], false); $course_category->aggregation = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATION']['0']['#'], false); $course_category->keephigh = backup_todb($cinfo['GRADE_CATEGORY']['#']['KEEPHIGH']['0']['#'], false); $course_category->droplow = backup_todb($cinfo['GRADE_CATEGORY']['#']['DROPLOW']['0']['#'], false); $course_category->aggregateonlygraded = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEONLYGRADED']['0']['#'], false); $course_category->aggregateoutcomes = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEOUTCOMES']['0']['#'], false); $course_category->aggregatesubcats = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATESUBCATS']['0']['#'], false); $course_category->timecreated = backup_todb($cinfo['GRADE_CATEGORY']['#']['TIMECREATED']['0']['#'], false); $course_category->update('restore'); $status = backup_putid($restore->backup_unique_code, 'grade_categories', $oldcat, $course_category->id) && $status; $cached_categories[$oldcat] = $course_category; $grade_item = $course_category->get_grade_item(); } else { $oldparent = backup_todb($cinfo['GRADE_CATEGORY']['#']['PARENT']['0']['#'], false); if (empty($cached_categories[$oldparent])) { debugging('parent not found ' . $oldparent); continue; // parent not found, sorry } $grade_category = new grade_category(); $grade_category->courseid = $restore->course_id; $grade_category->parent = $cached_categories[$oldparent]->id; $grade_category->fullname = backup_todb($cinfo['GRADE_CATEGORY']['#']['FULLNAME']['0']['#'], false); $grade_category->aggregation = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATION']['0']['#'], false); $grade_category->keephigh = backup_todb($cinfo['GRADE_CATEGORY']['#']['KEEPHIGH']['0']['#'], false); $grade_category->droplow = backup_todb($cinfo['GRADE_CATEGORY']['#']['DROPLOW']['0']['#'], false); $grade_category->aggregateonlygraded = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEONLYGRADED']['0']['#'], false); $grade_category->aggregateoutcomes = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEOUTCOMES']['0']['#'], false); $grade_category->aggregatesubcats = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATESUBCATS']['0']['#'], false); $grade_category->timecreated = backup_todb($cinfo['GRADE_CATEGORY']['#']['TIMECREATED']['0']['#'], false); $grade_category->insert('restore'); $status = backup_putid($restore->backup_unique_code, 'grade_categories', $oldcat, $grade_category->id) && $status; $cached_categories[$oldcat] = $grade_category; $grade_item = $grade_category->get_grade_item(); // creates grade_item too } unset($cinfo); $idnumber = backup_todb($info['GRADE_ITEM']['#']['IDNUMBER']['0']['#'], false); if (grade_verify_idnumber($idnumber, $restore->course_id)) { $grade_item->idnumber = $idnumber; } $grade_item->itemname = backup_todb($info['GRADE_ITEM']['#']['ITEMNAME']['0']['#'], false); $grade_item->iteminfo = backup_todb($info['GRADE_ITEM']['#']['ITEMINFO']['0']['#'], false); $grade_item->gradetype = backup_todb($info['GRADE_ITEM']['#']['GRADETYPE']['0']['#'], false); $grade_item->calculation = backup_todb($info['GRADE_ITEM']['#']['CALCULATION']['0']['#'], false); $grade_item->grademax = backup_todb($info['GRADE_ITEM']['#']['GRADEMAX']['0']['#'], false); $grade_item->grademin = backup_todb($info['GRADE_ITEM']['#']['GRADEMIN']['0']['#'], false); $grade_item->gradepass = backup_todb($info['GRADE_ITEM']['#']['GRADEPASS']['0']['#'], false); $grade_item->multfactor = backup_todb($info['GRADE_ITEM']['#']['MULTFACTOR']['0']['#'], false); $grade_item->plusfactor = backup_todb($info['GRADE_ITEM']['#']['PLUSFACTOR']['0']['#'], false); $grade_item->aggregationcoef = backup_todb($info['GRADE_ITEM']['#']['AGGREGATIONCOEF']['0']['#'], false); $grade_item->display = backup_todb($info['GRADE_ITEM']['#']['DISPLAY']['0']['#'], false); $grade_item->decimals = backup_todb($info['GRADE_ITEM']['#']['DECIMALS']['0']['#'], false); $grade_item->hidden = backup_todb($info['GRADE_ITEM']['#']['HIDDEN']['0']['#'], false); $grade_item->locked = backup_todb($info['GRADE_ITEM']['#']['LOCKED']['0']['#'], false); $grade_item->locktime = backup_todb($info['GRADE_ITEM']['#']['LOCKTIME']['0']['#'], false); $grade_item->timecreated = backup_todb($info['GRADE_ITEM']['#']['TIMECREATED']['0']['#'], false); if (backup_todb($info['GRADE_ITEM']['#']['SCALEID']['0']['#'], false)) { $scale = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_ITEM']['#']['SCALEID']['0']['#'], false)); $grade_item->scaleid = $scale->new_id; } if (backup_todb($info['GRADE_ITEM']['#']['OUTCOMEID']['0']['#'], false)) { $outcome = backup_getid($restore->backup_unique_code, "grade_outcomes", backup_todb($info['GRADE_ITEM']['#']['OUTCOMEID']['0']['#'], false)); $grade_item->outcomeid = $outcome->new_id; } $grade_item->update('restore'); $status = backup_putid($restore->backup_unique_code, "grade_items", $rec->old_id, $grade_item->id) && $status; } else { if ($itemtype != 'mod' and (!$restoreall or $importing)) { // not extra gradebook stuff if restoring individual activities or something already there continue; } $dbrec = new object(); $dbrec->courseid = $restore->course_id; $dbrec->itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#'], false); $dbrec->itemmodule = backup_todb($info['GRADE_ITEM']['#']['ITEMMODULE']['0']['#'], false); if ($itemtype == 'mod') { // iteminstance should point to new mod $olditeminstance = backup_todb($info['GRADE_ITEM']['#']['ITEMINSTANCE']['0']['#'], false); $mod = backup_getid($restore->backup_unique_code, $dbrec->itemmodule, $olditeminstance); $dbrec->iteminstance = $mod->new_id; if (!($cm = get_coursemodule_from_instance($dbrec->itemmodule, $mod->new_id))) { // item not restored - no item continue; } // keep in sync with activity idnumber $dbrec->idnumber = $cm->idnumber; } else { $idnumber = backup_todb($info['GRADE_ITEM']['#']['IDNUMBER']['0']['#'], false); if (grade_verify_idnumber($idnumber, $restore->course_id)) { //make sure the new idnumber is unique $dbrec->idnumber = $idnumber; } } $dbrec->itemname = backup_todb($info['GRADE_ITEM']['#']['ITEMNAME']['0']['#'], false); $dbrec->itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#'], false); $dbrec->itemmodule = backup_todb($info['GRADE_ITEM']['#']['ITEMMODULE']['0']['#'], false); $dbrec->itemnumber = backup_todb($info['GRADE_ITEM']['#']['ITEMNUMBER']['0']['#'], false); $dbrec->iteminfo = backup_todb($info['GRADE_ITEM']['#']['ITEMINFO']['0']['#'], false); $dbrec->gradetype = backup_todb($info['GRADE_ITEM']['#']['GRADETYPE']['0']['#'], false); $dbrec->calculation = backup_todb($info['GRADE_ITEM']['#']['CALCULATION']['0']['#'], false); $dbrec->grademax = backup_todb($info['GRADE_ITEM']['#']['GRADEMAX']['0']['#'], false); $dbrec->grademin = backup_todb($info['GRADE_ITEM']['#']['GRADEMIN']['0']['#'], false); $dbrec->gradepass = backup_todb($info['GRADE_ITEM']['#']['GRADEPASS']['0']['#'], false); $dbrec->multfactor = backup_todb($info['GRADE_ITEM']['#']['MULTFACTOR']['0']['#'], false); $dbrec->plusfactor = backup_todb($info['GRADE_ITEM']['#']['PLUSFACTOR']['0']['#'], false); $dbrec->aggregationcoef = backup_todb($info['GRADE_ITEM']['#']['AGGREGATIONCOEF']['0']['#'], false); $dbrec->display = backup_todb($info['GRADE_ITEM']['#']['DISPLAY']['0']['#'], false); $dbrec->decimals = backup_todb($info['GRADE_ITEM']['#']['DECIMALS']['0']['#'], false); $dbrec->hidden = backup_todb($info['GRADE_ITEM']['#']['HIDDEN']['0']['#'], false); $dbrec->locked = backup_todb($info['GRADE_ITEM']['#']['LOCKED']['0']['#'], false); $dbrec->locktime = backup_todb($info['GRADE_ITEM']['#']['LOCKTIME']['0']['#'], false); $dbrec->timecreated = backup_todb($info['GRADE_ITEM']['#']['TIMECREATED']['0']['#'], false); if (backup_todb($info['GRADE_ITEM']['#']['SCALEID']['0']['#'], false)) { $scale = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_ITEM']['#']['SCALEID']['0']['#'], false)); $dbrec->scaleid = $scale->new_id; } if (backup_todb($info['GRADE_ITEM']['#']['OUTCOMEID']['0']['#'])) { $oldoutcome = backup_todb($info['GRADE_ITEM']['#']['OUTCOMEID']['0']['#']); if (empty($outcomes[$oldoutcome])) { continue; // error! } if (empty($outcomes[$oldoutcome]->id)) { $outcomes[$oldoutcome]->insert('restore'); $outcomes[$oldoutcome]->use_in($restore->course_id); backup_putid($restore->backup_unique_code, "grade_outcomes", $oldoutcome, $outcomes[$oldoutcome]->id); } $dbrec->outcomeid = $outcomes[$oldoutcome]->id; } $grade_item = new grade_item($dbrec, false); $grade_item->insert('restore'); if ($restoreall) { // set original parent if restored $oldcat = $info['GRADE_ITEM']['#']['CATEGORYID']['0']['#']; if (!empty($cached_categories[$oldcat])) { $grade_item->set_parent($cached_categories[$oldcat]->id); } } $status = backup_putid($restore->backup_unique_code, "grade_items", $rec->old_id, $grade_item->id) && $status; } // no need to restore grades if user data is not selected or importing activities if ($importing or $grade_item->itemtype == 'mod' and !restore_userdata_selected($restore, $grade_item->itemmodule, $olditeminstance)) { // module instance not selected when restored using granular // skip this item continue; } /// now, restore grade_grades if (!empty($info['GRADE_ITEM']['#']['GRADE_GRADES']['0']['#']['GRADE'])) { //Iterate over items foreach ($info['GRADE_ITEM']['#']['GRADE_GRADES']['0']['#']['GRADE'] as $g_info) { $grade = new grade_grade(); $grade->itemid = $grade_item->id; $olduser = backup_todb($g_info['#']['USERID']['0']['#'], false); $user = backup_getid($restore->backup_unique_code, "user", $olduser); $grade->userid = $user->new_id; $grade->rawgrade = backup_todb($g_info['#']['RAWGRADE']['0']['#'], false); $grade->rawgrademax = backup_todb($g_info['#']['RAWGRADEMAX']['0']['#'], false); $grade->rawgrademin = backup_todb($g_info['#']['RAWGRADEMIN']['0']['#'], false); // need to find scaleid if (backup_todb($g_info['#']['RAWSCALEID']['0']['#'])) { $scale = backup_getid($restore->backup_unique_code, "scale", backup_todb($g_info['#']['RAWSCALEID']['0']['#'], false)); $grade->rawscaleid = $scale->new_id; } if (backup_todb($g_info['#']['USERMODIFIED']['0']['#'])) { if ($modifier = backup_getid($restore->backup_unique_code, "user", backup_todb($g_info['#']['USERMODIFIED']['0']['#'], false))) { $grade->usermodified = $modifier->new_id; } } $grade->finalgrade = backup_todb($g_info['#']['FINALGRADE']['0']['#'], false); $grade->hidden = backup_todb($g_info['#']['HIDDEN']['0']['#'], false); $grade->locked = backup_todb($g_info['#']['LOCKED']['0']['#'], false); $grade->locktime = backup_todb($g_info['#']['LOCKTIME']['0']['#'], false); $grade->exported = backup_todb($g_info['#']['EXPORTED']['0']['#'], false); $grade->overridden = backup_todb($g_info['#']['OVERRIDDEN']['0']['#'], false); $grade->excluded = backup_todb($g_info['#']['EXCLUDED']['0']['#'], false); $grade->feedback = backup_todb($g_info['#']['FEEDBACK']['0']['#'], false); $grade->feedbackformat = backup_todb($g_info['#']['FEEDBACKFORMAT']['0']['#'], false); $grade->information = backup_todb($g_info['#']['INFORMATION']['0']['#'], false); $grade->informationformat = backup_todb($g_info['#']['INFORMATIONFORMAT']['0']['#'], false); $grade->timecreated = backup_todb($g_info['#']['TIMECREATED']['0']['#'], false); $grade->timemodified = backup_todb($g_info['#']['TIMEMODIFIED']['0']['#'], false); $grade->insert('restore'); backup_putid($restore->backup_unique_code, "grade_grades", backup_todb($g_info['#']['ID']['0']['#']), $grade->id); $counter++; if ($counter % 20 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 400 == 0) { echo "<br />"; } } backup_flush(300); } } } } } } } /// add outcomes that are not used when doing full restore if ($status and $restoreall) { foreach ($outcomes as $oldoutcome => $grade_outcome) { if (empty($grade_outcome->id)) { $grade_outcome->insert('restore'); $grade_outcome->use_in($restore->course_id); backup_putid($restore->backup_unique_code, "grade_outcomes", $oldoutcome, $grade_outcome->id); } } } if ($status and !$importing and $restore_histories) { /// following code is very inefficient $gchcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'grade_categories_history'); $gghcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'grade_grades_history'); $gihcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'grade_items_history'); $gohcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'grade_outcomes_history'); // Number of records to get in every chunk $recordset_size = 2; // process histories if ($gchcount && $status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradecategoryhistory', 'grades') . '</li>'; } $counter = 0; while ($counter < $gchcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_categories_history' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_categories_history', $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug $oldobj = backup_getid($restore->backup_unique_code, "grade_categories", backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['OLDID']['0']['#'])); if (empty($oldobj->new_id)) { // if the old object is not being restored, can't restoring its history $counter++; continue; } $dbrec->oldid = $oldobj->new_id; $dbrec->action = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['ACTION']['0']['#']); $dbrec->source = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['SOURCE']['0']['#']); $dbrec->timemodified = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['TIMEMODIFIED']['0']['#']); // loggeduser might not be restored, e.g. admin if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['LOGGEDUSER']['0']['#']))) { $dbrec->loggeduser = $oldobj->new_id; } // this item might not have a parent at all, do not skip it if no parent is specified if (backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['PARENT']['0']['#'])) { $oldobj = backup_getid($restore->backup_unique_code, "grade_categories", backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['PARENT']['0']['#'])); if (empty($oldobj->new_id)) { // if the parent category not restored $counter++; continue; } } $dbrec->parent = $oldobj->new_id; $dbrec->depth = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['DEPTH']['0']['#']); // path needs to be rebuilt if ($path = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['PATH']['0']['#'])) { // to preserve the path and make it work, we need to replace the categories one by one // we first get the list of categories in current path if ($paths = explode("/", $path)) { $newpath = ''; foreach ($paths as $catid) { if ($catid) { // find the new corresponding path $oldpath = backup_getid($restore->backup_unique_code, "grade_categories", $catid); $newpath .= "/{$oldpath->new_id}"; } } $dbrec->path = $newpath; } } $dbrec->fullname = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['FULLNAME']['0']['#']); $dbrec->aggregation = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['AGGRETGATION']['0']['#']); $dbrec->keephigh = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['KEEPHIGH']['0']['#']); $dbrec->droplow = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['DROPLOW']['0']['#']); $dbrec->aggregateonlygraded = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['AGGREGATEONLYGRADED']['0']['#']); $dbrec->aggregateoutcomes = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['AGGREGATEOUTCOMES']['0']['#']); $dbrec->aggregatesubcats = backup_todb($info['GRADE_CATEGORIES_HISTORY']['#']['AGGREGATESUBCATS']['0']['#']); $dbrec->courseid = $restore->course_id; insert_record('grade_categories_history', $dbrec); unset($dbrec); } //Increment counters $counter++; //Do some output if ($counter % 1 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 20 == 0) { echo "<br />"; } } backup_flush(300); } } } } } // process histories if ($gghcount && $status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradegradeshistory', 'grades') . '</li>'; } $counter = 0; while ($counter < $gghcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_grades_history' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_grades_history', $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug $oldobj = backup_getid($restore->backup_unique_code, "grade_grades", backup_todb($info['GRADE_GRADES_HISTORY']['#']['OLDID']['0']['#'])); if (empty($oldobj->new_id)) { // if the old object is not being restored, can't restoring its history $counter++; continue; } $dbrec->oldid = $oldobj->new_id; $dbrec->action = backup_todb($info['GRADE_GRADES_HISTORY']['#']['ACTION']['0']['#']); $dbrec->source = backup_todb($info['GRADE_GRADES_HISTORY']['#']['SOURCE']['0']['#']); $dbrec->timemodified = backup_todb($info['GRADE_GRADES_HISTORY']['#']['TIMEMODIFIED']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_GRADES_HISTORY']['#']['LOGGEDUSER']['0']['#']))) { $dbrec->loggeduser = $oldobj->new_id; } $oldobj = backup_getid($restore->backup_unique_code, "grade_items", backup_todb($info['GRADE_GRADES_HISTORY']['#']['ITEMID']['0']['#'])); $dbrec->itemid = $oldobj->new_id; if (empty($dbrec->itemid)) { $counter++; continue; // grade item not being restored } $oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_GRADES_HISTORY']['#']['USERID']['0']['#'])); $dbrec->userid = $oldobj->new_id; $dbrec->rawgrade = backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWGRADE']['0']['#']); $dbrec->rawgrademax = backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWGRADEMAX']['0']['#']); $dbrec->rawgrademin = backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWGRADEMIN']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_GRADES_HISTORY']['#']['USERMODIFIED']['0']['#']))) { $dbrec->usermodified = $oldobj->new_id; } if (backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWSCALEID']['0']['#'])) { $scale = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_GRADES_HISTORY']['#']['RAWSCALEID']['0']['#'])); $dbrec->rawscaleid = $scale->new_id; } $dbrec->finalgrade = backup_todb($info['GRADE_GRADES_HISTORY']['#']['FINALGRADE']['0']['#']); $dbrec->hidden = backup_todb($info['GRADE_GRADES_HISTORY']['#']['HIDDEN']['0']['#']); $dbrec->locked = backup_todb($info['GRADE_GRADES_HISTORY']['#']['LOCKED']['0']['#']); $dbrec->locktime = backup_todb($info['GRADE_GRADES_HISTORY']['#']['LOCKTIME']['0']['#']); $dbrec->exported = backup_todb($info['GRADE_GRADES_HISTORY']['#']['EXPORTED']['0']['#']); $dbrec->overridden = backup_todb($info['GRADE_GRADES_HISTORY']['#']['OVERRIDDEN']['0']['#']); $dbrec->excluded = backup_todb($info['GRADE_GRADES_HISTORY']['#']['EXCLUDED']['0']['#']); $dbrec->feedback = backup_todb($info['GRADE_TEXT_HISTORY']['#']['FEEDBACK']['0']['#']); $dbrec->feedbackformat = backup_todb($info['GRADE_TEXT_HISTORY']['#']['FEEDBACKFORMAT']['0']['#']); $dbrec->information = backup_todb($info['GRADE_TEXT_HISTORY']['#']['INFORMATION']['0']['#']); $dbrec->informationformat = backup_todb($info['GRADE_TEXT_HISTORY']['#']['INFORMATIONFORMAT']['0']['#']); insert_record('grade_grades_history', $dbrec); unset($dbrec); } //Increment counters $counter++; //Do some output if ($counter % 1 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 20 == 0) { echo "<br />"; } } backup_flush(300); } } } } } // process histories if ($gihcount && $status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeitemshistory', 'grades') . '</li>'; } $counter = 0; while ($counter < $gihcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_items_history' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_items_history', $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug $oldobj = backup_getid($restore->backup_unique_code, "grade_items", backup_todb($info['GRADE_ITEM_HISTORY']['#']['OLDID']['0']['#'])); if (empty($oldobj->new_id)) { // if the old object is not being restored, can't restoring its history $counter++; continue; } $dbrec->oldid = $oldobj->new_id; $dbrec->action = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ACTION']['0']['#']); $dbrec->source = backup_todb($info['GRADE_ITEM_HISTORY']['#']['SOURCE']['0']['#']); $dbrec->timemodified = backup_todb($info['GRADE_ITEM_HISTORY']['#']['TIMEMODIFIED']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_ITEM_HISTORY']['#']['LOGGEDUSER']['0']['#']))) { $dbrec->loggeduser = $oldobj->new_id; } $dbrec->courseid = $restore->course_id; $oldobj = backup_getid($restore->backup_unique_code, 'grade_categories', backup_todb($info['GRADE_ITEM_HISTORY']['#']['CATEGORYID']['0']['#'])); $oldobj->categoryid = $category->new_id; if (empty($oldobj->categoryid)) { $counter++; continue; // category not restored } $dbrec->itemname = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMNAME']['0']['#']); $dbrec->itemtype = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMTYPE']['0']['#']); $dbrec->itemmodule = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMMODULE']['0']['#']); // code from grade_items restore $iteminstance = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMINSTANCE']['0']['#']); // do not restore if this grade_item is a mod, and if ($dbrec->itemtype == 'mod') { if (!restore_userdata_selected($restore, $dbrec->itemmodule, $iteminstance)) { // module instance not selected when restored using granular // skip this item $counter++; continue; } // iteminstance should point to new mod $mod = backup_getid($restore->backup_unique_code, $dbrec->itemmodule, $iteminstance); $dbrec->iteminstance = $mod->new_id; } else { if ($dbrec->itemtype == 'category') { // the item instance should point to the new grade category // only proceed if we are restoring all grade items if ($restoreall) { $category = backup_getid($restore->backup_unique_code, 'grade_categories', $iteminstance); $dbrec->iteminstance = $category->new_id; } else { // otherwise we can safely ignore this grade item and subsequent // grade_raws, grade_finals etc continue; } } elseif ($dbrec->itemtype == 'course') { // We don't restore course type to avoid duplicate course items if ($restoreall) { // TODO any special code needed here to restore course item without duplicating it? // find the course category with depth 1, and course id = current course id // this would have been already restored $cat = get_record('grade_categories', 'depth', 1, 'courseid', $restore->course_id); $dbrec->iteminstance = $cat->id; } else { $counter++; continue; } } } $dbrec->itemnumber = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMNUMBER']['0']['#']); $dbrec->iteminfo = backup_todb($info['GRADE_ITEM_HISTORY']['#']['ITEMINFO']['0']['#']); $dbrec->idnumber = backup_todb($info['GRADE_ITEM_HISTORY']['#']['IDNUMBER']['0']['#']); $dbrec->calculation = backup_todb($info['GRADE_ITEM_HISTORY']['#']['CALCULATION']['0']['#']); $dbrec->gradetype = backup_todb($info['GRADE_ITEM_HISTORY']['#']['GRADETYPE']['0']['#']); $dbrec->grademax = backup_todb($info['GRADE_ITEM_HISTORY']['#']['GRADEMAX']['0']['#']); $dbrec->grademin = backup_todb($info['GRADE_ITEM_HISTORY']['#']['GRADEMIN']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_ITEM_HISTORY']['#']['SCALEID']['0']['#']))) { // scaleid is optional $dbrec->scaleid = $oldobj->new_id; } if ($oldobj = backup_getid($restore->backup_unique_code, "grade_outcomes", backup_todb($info['GRADE_ITEM_HISTORY']['#']['OUTCOMEID']['0']['#']))) { // outcome is optional $dbrec->outcomeid = $oldobj->new_id; } $dbrec->gradepass = backup_todb($info['GRADE_ITEM_HISTORY']['#']['GRADEPASS']['0']['#']); $dbrec->multfactor = backup_todb($info['GRADE_ITEM_HISTORY']['#']['MULTFACTOR']['0']['#']); $dbrec->plusfactor = backup_todb($info['GRADE_ITEM_HISTORY']['#']['PLUSFACTOR']['0']['#']); $dbrec->aggregationcoef = backup_todb($info['GRADE_ITEM_HISTORY']['#']['AGGREGATIONCOEF']['0']['#']); $dbrec->sortorder = backup_todb($info['GRADE_ITEM_HISTORY']['#']['SORTORDER']['0']['#']); $dbrec->display = backup_todb($info['GRADE_ITEM_HISTORY']['#']['DISPLAY']['0']['#']); $dbrec->decimals = backup_todb($info['GRADE_ITEM_HISTORY']['#']['DECIMALS']['0']['#']); $dbrec->hidden = backup_todb($info['GRADE_ITEM_HISTORY']['#']['HIDDEN']['0']['#']); $dbrec->locked = backup_todb($info['GRADE_ITEM_HISTORY']['#']['LOCKED']['0']['#']); $dbrec->locktime = backup_todb($info['GRADE_ITEM_HISTORY']['#']['LOCKTIME']['0']['#']); $dbrec->needsupdate = backup_todb($info['GRADE_ITEM_HISTORY']['#']['NEEDSUPDATE']['0']['#']); insert_record('grade_items_history', $dbrec); unset($dbrec); } //Increment counters $counter++; //Do some output if ($counter % 1 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 20 == 0) { echo "<br />"; } } backup_flush(300); } } } } } // process histories if ($gohcount && $status) { if (!defined('RESTORE_SILENTLY')) { echo '<li>' . get_string('gradeoutcomeshistory', 'grades') . '</li>'; } $counter = 0; while ($counter < $gohcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'grade_outcomes_history' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, 'grade_outcomes_history', $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug $oldobj = backup_getid($restore->backup_unique_code, "grade_outcomes", backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['OLDID']['0']['#'])); if (empty($oldobj->new_id)) { // if the old object is not being restored, can't restoring its history $counter++; continue; } $dbrec->oldid = $oldobj->new_id; $dbrec->action = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['ACTION']['0']['#']); $dbrec->source = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['SOURCE']['0']['#']); $dbrec->timemodified = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['TIMEMODIFIED']['0']['#']); if ($oldobj = backup_getid($restore->backup_unique_code, "user", backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['LOGGEDUSER']['0']['#']))) { $dbrec->loggeduser = $oldobj->new_id; } $dbrec->courseid = $restore->course_id; $dbrec->shortname = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['SHORTNAME']['0']['#']); $dbrec->fullname = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['FULLNAME']['0']['#']); $oldobj = backup_getid($restore->backup_unique_code, "scale", backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['SCALEID']['0']['#'])); $dbrec->scaleid = $oldobj->new_id; $dbrec->description = backup_todb($info['GRADE_OUTCOME_HISTORY']['#']['DESCRIPTION']['0']['#']); insert_record('grade_outcomes_history', $dbrec); unset($dbrec); } //Increment counters $counter++; //Do some output if ($counter % 1 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 20 == 0) { echo "<br />"; } } backup_flush(300); } } } } } } if (!defined('RESTORE_SILENTLY')) { //End ul echo '</ul>'; } return $status; }
/** * Get and update/create grade item for legacy modules. */ function grade_get_legacy_grade_item($modinstance, $grademax, $scaleid) { // does it already exist? if ($grade_items = grade_item::fetch_all(array('courseid' => $modinstance->course, 'itemtype' => 'mod', 'itemmodule' => $modinstance->modname, 'iteminstance' => $modinstance->id, 'itemnumber' => 0))) { if (count($grade_items) > 1) { debugging('Multiple legacy grade_items found.'); return false; } $grade_item = reset($grade_items); if (is_null($grademax) and is_null($scaleid)) { $grade_item->gradetype = GRADE_TYPE_NONE; } else { if ($scaleid) { $grade_item->gradetype = GRADE_TYPE_SCALE; $grade_item->scaleid = $scaleid; $grade_item->grademin = 1; } else { $grade_item->gradetype = GRADE_TYPE_VALUE; $grade_item->grademax = $grademax; $grade_item->grademin = 0; } } $grade_item->itemname = $modinstance->name; $grade_item->idnumber = $modinstance->cmidnumber; $grade_item->update(); return $grade_item; } // create new one $params = array('courseid' => $modinstance->course, 'itemtype' => 'mod', 'itemmodule' => $modinstance->modname, 'iteminstance' => $modinstance->id, 'itemnumber' => 0, 'itemname' => $modinstance->name, 'idnumber' => $modinstance->cmidnumber); if (is_null($grademax) and is_null($scaleid)) { $params['gradetype'] = GRADE_TYPE_NONE; } else { if ($scaleid) { $params['gradetype'] = GRADE_TYPE_SCALE; $params['scaleid'] = $scaleid; $grade_item->grademin = 1; } else { $params['gradetype'] = GRADE_TYPE_VALUE; $params['grademax'] = $grademax; $params['grademin'] = 0; } } $grade_item = new grade_item($params); $grade_item->insert(); return $grade_item; }
protected function process_grade_item($data) { global $DB; $data = (object) $data; $oldid = $data->id; // We'll need these later $oldparentid = $data->categoryid; $courseid = $this->get_courseid(); $idnumber = null; if (!empty($data->idnumber)) { // Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber // Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop) // so the best is to keep the ones already in the gradebook // Potential problem: duplicates if same items are restored more than once. :-( // This needs to be fixed in some way (outcomes & activities with multiple items) // $data->idnumber = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber; // In any case, verify always for uniqueness $sql = "SELECT cm.id\n FROM {course_modules} cm\n WHERE cm.course = :courseid AND\n cm.idnumber = :idnumber AND\n cm.id <> :cmid"; $params = array('courseid' => $courseid, 'idnumber' => $data->idnumber, 'cmid' => $this->task->get_moduleid()); if (!$DB->record_exists_sql($sql, $params) && !$DB->record_exists('grade_items', array('courseid' => $courseid, 'idnumber' => $data->idnumber))) { $idnumber = $data->idnumber; } } if (!empty($data->categoryid)) { // If the grade category id of the grade item being restored belongs to this course // then it is a fair assumption that this is the correct grade category for the activity // and we should leave it in place, if not then unset it. // TODO MDL-34790 Gradebook does not import if target course has gradebook categories. $conditions = array('id' => $data->categoryid, 'courseid' => $courseid); if (!$this->task->is_samesite() || !$DB->record_exists('grade_categories', $conditions)) { unset($data->categoryid); } } unset($data->id); $data->courseid = $this->get_courseid(); $data->iteminstance = $this->task->get_activityid(); $data->idnumber = $idnumber; $data->scaleid = $this->get_mappingid('scale', $data->scaleid); $data->outcomeid = $this->get_mappingid('outcome', $data->outcomeid); $data->timecreated = $this->apply_date_offset($data->timecreated); $data->timemodified = $this->apply_date_offset($data->timemodified); $gradeitem = new grade_item($data, false); $gradeitem->insert('restore'); //sortorder is automatically assigned when inserting. Re-instate the previous sortorder $gradeitem->sortorder = $data->sortorder; $gradeitem->update('restore'); // Set mapping, saving the original category id into parentitemid // gradebook restore (final task) will need it to reorganise items $this->set_mapping('grade_item', $oldid, $gradeitem->id, false, null, $oldparentid); }
/** * Tests update grade service with existing regular manual items with the same name * as requested. Should update the first item and turn it into mhaairs item. Should not change * any item property other than the item instance. * * @return void */ public function test_update_item_with_manual_item() { global $DB; $this->set_user('admin'); $this->assertEquals(0, $DB->count_records('grade_items')); $catname = 'Existing grade category'; $itemname = 'Existing grade item'; // Create category. $catparams = array('fullname' => $catname, 'courseid' => $this->course->id, 'hidden' => false); $category = new \grade_category($catparams, false); $category->id = $category->insert(); // Add two manual grade item directly. $itemparams = array('courseid' => $this->course->id, 'itemtype' => 'manual', 'itemname' => $itemname, 'categoryid' => $category->id); $gitem = new \grade_item($itemparams, false); $gitem->insert('manual'); $gitem = new \grade_item($itemparams, false); $gitem->insert('manual'); // There should be 4 items (including course and category items). $itemcount = $DB->count_records('grade_items'); $this->assertEquals(4, $itemcount); $service = 'block_mhaairs_gradebookservice_external::update_grade'; $itemdetails = array('itemname' => $itemname, 'grademax' => 90, 'useexisting' => 1, 'categoryid' => 'New grade category'); $itemdetailsjson = urlencode(json_encode($itemdetails)); // Update item via service. $servicedata = array(); $servicedata['source'] = 'mhaairs'; $servicedata['courseid'] = 'tc1'; $servicedata['itemtype'] = 'manual'; $servicedata['itemmodule'] = 'mhaairs'; $servicedata['iteminstance'] = 345; $servicedata['itemnumber'] = 0; $servicedata['grades'] = null; $servicedata['itemdetails'] = $itemdetailsjson; $result = call_user_func_array($service, $servicedata); // 2 grade categories overall. $itemcount = $DB->count_records('grade_categories'); $this->assertEquals(2, $itemcount); // 4 grade items overall. $itemcount = $DB->count_records('grade_items'); $this->assertEquals(4, $itemcount); // 2 manual items remaining. $itemcount = $DB->count_records('grade_items', array('itemtype' => 'manual')); $this->assertEquals(2, $itemcount); // 1 mhaairs item. $itemcount = $DB->count_records('grade_items', array('itemtype' => 'manual', 'itemmodule' => 'mhaairs')); $this->assertEquals(1, $itemcount); // 1 mhaairs item with the item instance and original grade. $itemcount = $DB->count_records('grade_items', array('itemtype' => 'manual', 'itemmodule' => 'mhaairs', 'iteminstance' => 345, 'grademax' => 100.0, 'categoryid' => $category->id)); $this->assertEquals(1, $itemcount); }
/** * 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}); }
protected function sub_test_scale_one_item() { $params = new stdClass(); $params->name = 'unittestscale1i'; $params->courseid = $this->course->id; $params->userid = $this->userid; $params->scale = 'Like'; $params->description = 'This scale is used to like something.'; $params->timemodified = time(); $scale = new grade_scale($params, false); $scale->load_items(); $this->assertCount(1, $scale->scale_items); $this->assertSame(array('Like'), $scale->scale_items); $this->assertSame('Like', $scale->compact_items()); $scale->insert(); // Manual grade item with 1 item scale. $grade_item = new stdClass(); $grade_item->courseid = $this->course->id; $grade_item->categoryid = $this->grade_categories[0]->id; $grade_item->itemname = 'manual grade_item scale_1'; $grade_item->itemtype = 'manual'; $grade_item->itemnumber = 0; $grade_item->needsupdate = false; $grade_item->gradetype = GRADE_TYPE_SCALE; $grade_item->scaleid = $scale->id; $grade_item->iteminfo = 'Manual grade item used for unit testing'; $grade_item->timecreated = time(); $grade_item->timemodified = time(); $grade_item = new grade_item($grade_item); $grade_item->insert(); $this->assertNotEmpty($grade_item->id); $this->assertEquals(1, $grade_item->grademin); $this->assertEquals(1, $grade_item->grademax); }
private static function save_grade_item($grade_item) { if (!$grade_item) { throw new InvalidArgumentException("grade_item must be set"); } if (!$grade_item->courseid) { throw new InvalidArgumentException("grade_item->courseid must be set"); } if (!$grade_item->categoryid) { throw new InvalidArgumentException("grade_item->categoryid must be set"); } if (!$grade_item->name) { throw new InvalidArgumentException("grade_item->name must be set"); } if (!isset($grade_item->item_number)) { $grade_item->item_number = 0; } // check for an existing item and update or create $grade_item_tosave = grade_item::fetch(array('courseid' => $grade_item->courseid, 'itemmodule' => self::GRADE_ITEM_MODULE, 'itemname' => $grade_item->name)); if (!$grade_item_tosave) { // create new one $grade_item_tosave = new grade_item(); $grade_item_tosave->itemmodule = self::GRADE_ITEM_MODULE; $grade_item_tosave->courseid = $grade_item->courseid; $grade_item_tosave->categoryid = $grade_item->categoryid; $grade_item_tosave->iteminfo = $grade_item->typename; //$grade_item_tosave->iteminfo = $grade_item->name.' '.$grade_item->type.' '.self::GRADE_CATEGORY_NAME; $grade_item_tosave->itemnumber = $grade_item->item_number; //$grade_item_tosave->idnumber = $grade_item->name; $grade_item_tosave->itemname = $grade_item->name; $grade_item_tosave->itemtype = self::GRADE_ITEM_TYPE; //$grade_item_tosave->itemmodule = self::GRADE_ITEM_MODULE; if (isset($grade_item->points_possible) && $grade_item->points_possible > 0) { $grade_item_tosave->grademax = $grade_item->points_possible; } $grade_item_tosave->insert(self::GRADE_LOCATION_STR); } else { // update if (isset($grade_item->points_possible) && $grade_item->points_possible > 0) { $grade_item_tosave->grademax = $grade_item->points_possible; } $grade_item_tosave->categoryid = $grade_item->categoryid; $grade_item_tosave->iteminfo = $grade_item->typename; $grade_item_tosave->update(self::GRADE_LOCATION_STR); } $grade_item_id = $grade_item_tosave->id; $grade_item_pp = $grade_item_tosave->grademax; // now save the related scores if (isset($grade_item->scores) && !empty($grade_item->scores)) { // get the existing scores $current_scores = array(); $existing_grades = grade_grade::fetch_all(array('itemid' => $grade_item_id)); if ($existing_grades) { foreach ($existing_grades as $grade) { $current_scores[$grade->userid] = $grade; } } // run through the scores in the gradeitem and try to save them $errors_count = 0; $processed_scores = array(); foreach ($grade_item->scores as $score) { $user = self::get_users($score->user_id); if (!$user) { $score->error = self::USER_DOES_NOT_EXIST_ERROR; $processed_scores[] = $score; $errors_count++; continue; } $user_id = $user->id; // null/blank scores are not allowed if (!isset($score->score)) { $score->error = 'NO_SCORE_ERROR'; $processed_scores[] = $score; $errors_count++; continue; } if (!is_numeric($score->score)) { $score->error = 'SCORE_INVALID'; $processed_scores[] = $score; $errors_count++; continue; } $score->score = floatval($score->score); // Student Score should not be greater than the total points possible if ($score->score > $grade_item_pp) { $score->error = self::POINTS_POSSIBLE_UPDATE_ERRORS; $processed_scores[] = $score; $errors_count++; continue; } try { $grade_tosave = null; if (isset($current_scores[$user_id])) { // existing score $grade_tosave = $current_scores[$user_id]; // check against existing score if ($score->score < $grade_tosave->rawgrade) { $score->error = self::SCORE_UPDATE_ERRORS; $processed_scores[] = $score; $errors_count++; continue; } $grade_tosave->finalgrade = $score->score; $grade_tosave->rawgrade = $score->score; $grade_tosave->timemodified = time(); /** @noinspection PhpUndefinedMethodInspection */ $grade_tosave->update(self::GRADE_LOCATION_STR); } else { // new score $grade_tosave = new grade_grade(); $grade_tosave->itemid = $grade_item_id; $grade_tosave->userid = $user_id; $grade_tosave->finalgrade = $score->score; $grade_tosave->rawgrade = $score->score; $grade_tosave->rawgrademax = $grade_item_pp; $now = time(); $grade_tosave->timecreated = $now; $grade_tosave->timemodified = $now; $grade_tosave->insert(self::GRADE_LOCATION_STR); } /** @noinspection PhpUndefinedFieldInspection */ $grade_tosave->user_id = $score->user_id; $processed_scores[] = $grade_tosave; } catch (Exception $e) { // General errors, caused while performing updates (Tag: generalerrors) $score->error = self::GENERAL_ERRORS; $processed_scores[] = $score; $errors_count++; } } /** @noinspection PhpUndefinedFieldInspection */ $grade_item_tosave->scores = $processed_scores; // put the errors in the item if ($errors_count > 0) { $errors = array(); foreach ($processed_scores as $score) { if (isset($score->error)) { $errors[$score->user_id] = $score->error; } } /** @noinspection PhpUndefinedFieldInspection */ $grade_item_tosave->errors = $errors; } $grade_item_tosave->force_regrading(); } return $grade_item_tosave; }
/** * This is the function which runs when cron calls. */ public function execute() { global $CFG, $DB; echo "BEGIN >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n"; /** * A script, to be run overnight, to pull L3VA scores from Leap and generate * the MAG, for each student on specifically-tagged courses, and add it into * our live Moodle. * * @copyright 2014-2015 Paul Vaughan * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ // Script start time. $time_start = microtime(true); // Null or an int (course's id): run the script only for this course. For testing or one-offs. // TODO: Consider changing $thiscourse as an array, not an integer. $thiscourse = null; // null or e.g. 1234 // TODO: can we use *all* the details in version.php? It would make a lot more sense. $version = '1.0.20'; //$build = '20150128'; $build = get_config('block_leap', 'version'); // Debugging. define('DEBUG', true); // Debugging. define('TRUNCATE_LOG', true); // Truncate the log table. if (TRUNCATE_LOG) { echo 'Truncating block_leap_log...'; $DB->delete_records('block_leap_log', null); echo " done.\n"; } overnight::tlog('GradeTracker script, v' . $version . ', ' . $build . '.', 'hiya'); overnight::tlog('Started at ' . date('c', $time_start) . '.', ' go '); if ($thiscourse) { overnight::tlog('IMPORTANT! Processing only course \'' . $thiscourse . '\'.', 'warn'); } overnight::tlog('', '----'); // Before almost anything has the chance to fail, reset the fail delay setting back to 0. if (DEBUG) { if (!($reset = $DB->set_field('task_scheduled', 'faildelay', 0, array('component' => 'block_leap', 'classname' => '\\block_leap\\task\\overnight')))) { overnight::tlog('Scheduled task "fail delay" could not be reset.', 'warn'); } else { overnight::tlog('Scheduled task "fail delay" reset to 0.', 'dbug'); } } $leap_url = get_config('block_leap', 'leap_url'); $auth_token = get_config('block_leap', 'auth_token'); define('LEAP_API_URL', $leap_url . '/people/%s/views/courses.json?token=' . $auth_token); //overnight::tlog( 'Leap API URL: ' . LEAP_API_URL, 'dbug' ); // Number of decimal places in the processed targets (and elsewhere). define('DECIMALS', 3); // Search term to use when searching for courses to process. define('IDNUMBERLIKE', 'leapcore_%'); //define( 'IDNUMBERLIKE', 'leapcore_test' ); // Category details for the above columns to go into. define('CATNAME', get_string('gradebook:category_title', 'block_leap')); // Include some details. require dirname(__FILE__) . '/../../details.php'; // Logging array for the end-of-script summary. $logging = array('courses' => array(), 'students_processed' => array(), 'students_unique' => array(), 'no_l3va' => array(), 'not_updated' => array(), 'grade_types' => array('btec' => 0, 'a level' => 0, 'gcse' => 0, 'refer and pass' => 0, 'noscale' => 0, 'develop, pass' => 0), 'poor_grades' => array(), 'num' => array('courses' => 0, 'students_processed' => 0, 'students_unique' => 0, 'no_l3va' => 0, 'not_updated' => 0, 'grade_types' => 0, 'grade_types_in_use' => 0, 'poor_grades' => 0)); // Small array to store the GCSE English and maths grades from the JSON. $gcse = array('english' => null, 'maths' => null); // Just for internal use, defines the grade type (int) and what it is (string). $gradetypes = array(0 => 'None', 1 => 'Value', 2 => 'Scale', 3 => 'Text'); // Define the wanted column names (will appear in this order in the Gradebook, initially). // These column names are an integral part of this plugin and should not be changed. $column_names = array(get_string('gradebook:tag', 'block_leap') => get_string('gradebook:tag_desc', 'block_leap')); // Make an array keyed to the column names to store the grades in. $targets = array(); foreach ($column_names as $name => $desc) { $targets[strtolower($name)] = ''; } /** * The next section looks through all courses for those with a properly configured Leap block * and adds it (and the tracking configuration) to the $courses array. */ overnight::tlog('', '----'); $courses = $DB->get_records('course', null, null, 'id,shortname,fullname'); $allcourses = array(); foreach ($courses as $course) { if ($course->id != 1) { $coursecontext = \context_course::instance($course->id); if (!($blockrecord = $DB->get_record('block_instances', array('blockname' => 'leap', 'parentcontextid' => $coursecontext->id)))) { if (DEBUG) { overnight::tlog('No Leap block found for course "' . $course->id . '" (' . $course->shortname . ')', 'dbug'); } continue; } if (!($blockinstance = block_instance('leap', $blockrecord))) { if (DEBUG) { overnight::tlog('No Leap block instance found for course "' . $course->id . '" (' . $course->shortname . ')', 'dbug'); } continue; } if (isset($blockinstance->config->trackertype) && !empty($blockinstance->config->trackertype)) { $course->trackertype = $blockinstance->config->trackertype; $course->scalename = null; $course->scaleid = null; $course->gradeid = null; $allcourses[] = $course; if (DEBUG) { overnight::tlog('Tracker "' . $blockinstance->config->trackertype . '" found in course ' . $course->id . ' (' . $course->shortname . ')', 'dbug'); } } else { if (DEBUG) { overnight::tlog('<Tracker not found in course ' . $course->id . ' (' . $course->shortname . ')', 'dbug'); } } } // END if $course != 1 } // END foreach $courses as $course /* foreach ( $allcourses as $course ) { // Ignore the course with id = 1, as it's the front page. if ( $course->id == 1 ) { continue; } else { // First get course context. $coursecontext = \context_course::instance( $course->id ); $blockrecord = $DB->get_record( 'block_instances', array( 'blockname' => 'leap', 'parentcontextid' => $coursecontext->id ) ); $blockinstance = block_instance( 'leap', $blockrecord ); // Check and add trackertype and coursetype to the $course object. if ( isset( $blockinstance->config->trackertype ) && !empty( $blockinstance->config->trackertype ) ) //!empty( $blockinstance->config->trackertype ) && //isset( $blockinstance->config->coursetype ) && //!empty( $blockinstance->config->coursetype ) ) { $course->trackertype = $blockinstance->config->trackertype; //$course->coursetype = $blockinstance->config->coursetype; // Setting some more variables we'll need in due course. $course->scalename = null; $course->scaleid = null; $course->gradeid = null; // All good, so... $courses[] = $course; overnight::tlog( 'Course \'' . $course->fullname . '\' (' . $course->shortname . ') [' . $course->id . '] added to process list.', 'info'); if ( DEBUG ) { overnight::tlog( json_encode( $course ), 'dbug'); } } } } */ //var_dump($courses); exit(0); /* Example $courses array. array(2) { [0]=> object(stdClass)#91 (7) { ["id"]=> string(1) "2" ["shortname"]=> string(5) "TC101" ["fullname"]=> string(15) "Test Course 101" ["trackertype"]=> string(7) "english" ["coursetype"]=> string(14) "a2_englishlang" ["scalename"]=> string(0) "" ["scaleid"]=> NULL } [1]=> object(stdClass)#92 (7) { ["id"]=> string(1) "3" ["shortname"]=> string(5) "TC201" ["fullname"]=> string(15) "Test course 201" ["trackertype"]=> string(7) "english" ["coursetype"]=> string(6) "a2_law" ["scalename"]=> string(0) "" ["scaleid"]=> NULL } } */ $num_courses = count($allcourses); $cur_courses = 0; if ($num_courses == 0) { overnight::tlog('No courses found to process, so halting.', 'EROR'); // Returning false indicates failure. We didn't fail, just found no courses to process. return true; } overnight::tlog('', '----'); /** * Sets up each configured course with a category and columns within it. */ foreach ($allcourses as $course) { $cur_courses++; overnight::tlog('Processing course (' . $cur_courses . '/' . $num_courses . ') ' . $course->fullname . ' (' . $course->shortname . ') [' . $course->id . '] at ' . date('c', time()) . '.', 'info'); $logging['courses'][] = $course->fullname . ' (' . $course->shortname . ') [' . $course->id . '].'; //overnight::tlog( $course->coursetype, 'PVDB' ); /* We need to give serious thought to NOT doing this, as it's basically impossible to set the correct scale at this point. Grades and that: Develop / Pass - would be used for all pass only type qualifications but develop will be used instead of refer, retake, fail etc. U, G, F, E, D, C, B, A, A* - to be used for GCSE / A-level plus any others that have letter grades. Refer, Pass, Merit, Distinction. Refer, PP, PM, MM, MD, DD Refer, PPP, PPM, PMM, MMM, MMD, MDD, DDD Numbers from 0 - 100 - in traffic light systems the numbers will be compared and anything lower than the target will be red, higher than target will be green. */ /* // Work out the scale from the course type. if ( stristr( $course->coursetype, 'as_' ) || stristr( $course->coursetype, 'a2_' ) ) { $course->scalename = 'A Level'; } else if ( stristr( $course->coursetype, 'gcse_' ) ) { $course->scalename = 'GCSE'; } else if ( stristr( $course->coursetype, 'btec_' ) ) { $course->scalename = 'BTEC'; } overnight::tlog( 'Course ' . $course->id . ' appears to be a ' . $course->scalename . ' course.', 'info' ); // Get the scale ID. if ( !$moodlescale = $DB->get_record( 'scale', array( 'name' => $course->scalename ), 'id' ) ) { overnight::tlog( '- Could not find a scale called \'' . $course->scalename . '\' for course ' . $course->id . '.', 'warn' ); } else { // Scale located. $course->scaleid = $moodlescale->id; overnight::tlog( '- Scale called \'' . $course->scalename . '\' found with ID ' . $moodlescale->id . '.', 'info' ); } overnight::tlog( json_encode( $course ), '>dbg'); //var_dump($courses); exit(0); */ overnight::tlog(json_encode($course), '>dbg'); // Figure out the grade type and scale here, pulled directly from the course's gradebook's course itemtype. $coursegradescale = $DB->get_record('grade_items', array('courseid' => $course->id, 'itemtype' => 'course'), 'gradetype, scaleid'); $course->gradeid = $coursegradescale->gradetype; $course->scaleid = $coursegradescale->scaleid; overnight::tlog(json_encode($course), 'PVDB'); if ($course->gradeid == 2) { if ($coursescale = $DB->get_record('scale', array('id' => $course->scaleid))) { $course->scalename = $coursescale->name; $tolog = '- Scale \'' . $course->scaleid . '\' (' . $coursescale->name . ') found [' . $coursescale->scale . ']'; $tolog .= $coursescale->courseid ? ' (which is specific to course ' . $coursescale->courseid . ').' : ' (which is global).'; overnight::tlog($tolog, 'info'); } else { // If the scale doesn't exist that the course is using, this is a problem. overnight::tlog('- Gradetype \'2\' set, but no matching scale found.', 'warn'); } } overnight::tlog(json_encode($course), 'PVDB'); /* if ( $coursegradescale = $DB->get_record( 'grade_items', array( 'courseid' => $course->id, 'itemtype' => 'course' ), 'gradetype, scaleid' ) ) { $course->gradeid = $coursegradescale->gradetype; $course->scaleid = $coursegradescale->scaleid; overnight::tlog( 'Gradetype \'' . $course->gradeid . '\' (' . $gradetypes[$course->gradeid] . ') found.', 'info' ); // If the grade type is 2 / scale. if ( $course->gradeid == 2 ) { if ( $coursescale = $DB->get_record( 'scale', array( 'id' => $course->scaleid ) ) ) { $course->scalename = $coursescale->name; //$course->scaleid = $scaleid; //$course->coursetype = $coursescale->name; $tolog = '- Scale \'' . $course->scaleid . '\' (' . $course->scalename . ') found'; $tolog .= ( $coursescale->courseid ) ? ' (which is specific to course ' . $coursescale->courseid . ').' : ' (which is global).'; overnight::tlog( $tolog, 'info' ); } else { // If the scale doesn't exist that the course is using, this is a problem. overnight::tlog( '- Gradetype \'2\' set, but no matching scale found.', 'warn' ); } } else if ( $course->gradeid == 1 ) { // If the grade type is 1 / value. $course->scalename = 'noscale'; $course->scaleid = 1; // Already set, above. //$course->coursetype = 'Value'; $tolog = ' Using \'' . $gradetypes[$gradeid] . '\' gradetype.'; } } else { // Set it to default if no good scale could be found/used. $gradeid = 0; $scaleid = 0; overnight::tlog('No \'gradetype\' found, so using defaults instead.', 'info'); } // You may get errors here (unknown index IIRC) if no scalename is generated because a scale (or anything) hasn't been set // for that course (e.g. 'cos it's a new course). Catch this earlier! $logging['grade_types'][strtolower($course->scalename)]++; /** * Category checking: create or skip. */ if ($DB->get_record('grade_categories', array('courseid' => $course->id, 'fullname' => CATNAME))) { // Category exists, so skip creation. overnight::tlog('Category \'' . CATNAME . '\' already exists for course ' . $course->id . '.', 'skip'); } else { $grade_category = new \grade_category(); // Create a category for this course. $grade_category->courseid = $course->id; // Course id. $grade_category->fullname = CATNAME; // Set the category name (no description). $grade_category->sortorder = 1; // Need a better way of changing column order. $grade_category->hidden = 1; // Attempting to hide the totals. // Save all that... if (!($gc = $grade_category->insert())) { overnight::tlog('Category \'' . CATNAME . '\' could not be inserted for course ' . $course->id . '.', 'EROR'); return false; } else { overnight::tlog('Category \'' . CATNAME . '\' (' . $gc . ') created for course ' . $course->id . '.'); } } // We've either checked a category exists or created one, so this *should* always work. $cat_id = $DB->get_record('grade_categories', array('courseid' => $course->id, 'fullname' => CATNAME)); $cat_id = $cat_id->id; // One thing we need to do is set 'gradetype' to 0 on that newly created category, which prevents a category total showing // and the grades counting towards the total course grade. $DB->set_field_select('grade_items', 'gradetype', 0, "courseid = " . $course->id . " AND itemtype = 'category' AND iteminstance = " . $cat_id); /** * Column checking: create or update. */ // Step through each column name. foreach ($column_names as $col_name => $col_desc) { // Need to check for previously-created columns and force an update if they already exist. //if ( $DB->get_record('grade_items', array( 'courseid' => $course->id, 'itemname' => $col_name, 'itemtype' => 'manual' ) ) ) { // // Column exists, so update instead. // overnight::tlog('- Column \'' . $col_name . '\' already exists for course ' . $course->id . '.', 'skip'); //} else { $grade_item = new \grade_item(); // Create a new item object. $grade_item->courseid = $course->id; // Course id. $grade_item->itemtype = 'manual'; // Set the category name (no description). $grade_item->itemname = $col_name; // The item's name. $grade_item->iteminfo = $col_desc; // Description of the item. $grade_item->categoryid = $cat_id; // Set the immediate parent category. $grade_item->hidden = 0; // Don't want it hidden (by default). $grade_item->locked = 1; // Lock it (by default). // Per-column specifics. if ($col_name == 'TAG') { $grade_item->sortorder = 1; // In-category sort order. //$grade_item->gradetype = $course->gradeid; $grade_item->gradetype = 3; // Text field. //$grade_item->scaleid = $course->scaleid; //$grade_item->display = 1; // 'Real'. MIGHT need to seperate out options for BTEC and A Level. $grade_item->display = 0; // No frills. } //if ( $col_name == 'L3VA' ) { // // Lock the L3VA col as it's calculated elsewhere. // $grade_item->sortorder = 2; // $grade_item->locked = 1; // $grade_item->decimals = 0; // $grade_item->display = 1; // 'Real'. //} //if ( $col_name == 'MAG' ) { // $grade_item->sortorder = 3; // //$grade_item->locked = 1; // $grade_item->gradetype = $gradeid; // $grade_item->scaleid = $scaleid; // $grade_item->display = 1; // 'Real'. //} // Scale ID, generated earlier. An int, 0 or greater. // TODO: Check if we need this any more!! //$grade_item->scale = $course->scaleid; // Check to see if this record already exists, determining if we insert or update. if (!($grade_items_exists = $DB->get_record('grade_items', array('courseid' => $course->id, 'itemname' => $col_name, 'itemtype' => 'manual')))) { // INSERT a new record. if (!($gi = $grade_item->insert())) { overnight::tlog('- Column \'' . $col_name . '\' could not be inserted for course ' . $course->id . '.', 'EROR'); return false; } else { overnight::tlog('- Column \'' . $col_name . '\' created for course ' . $course->id . '.'); } } else { // UPDATE the existing record. $grade_item->id = $grade_items_exists->id; if (!($gi = $grade_item->update())) { overnight::tlog('- Column \'' . $col_name . '\' could not be updated for course ' . $course->id . '.', 'EROR'); return false; } else { overnight::tlog('- Column \'' . $col_name . '\' updated for course ' . $course->id . '.'); } } //} // END skip processing if manual column(s) already found in course. } // END while working through each rquired column. // Good to here. /** * Move the category to the first location in the gradebook if it isn't already. */ //$gtree = new grade_tree($course->id, false, false); //$temp = grade_edit_tree::move_elements(1, '') /** * Collect enrolments based on each of those courses */ // EPIC 'get enrolled students' query from Stack Overflow: // http://stackoverflow.com/questions/22161606/sql-query-for-courses-enrolment-on-moodle // Only selects manually enrolled, not self-enrolled student roles (redacted!). $sql = "SELECT DISTINCT u.id AS userid, firstname, lastname, username\n FROM mdl_user u\n JOIN mdl_user_enrolments ue ON ue.userid = u.id\n JOIN mdl_enrol e ON e.id = ue.enrolid\n -- AND e.enrol = 'leap'\n JOIN mdl_role_assignments ra ON ra.userid = u.id\n JOIN mdl_context ct ON ct.id = ra.contextid\n AND ct.contextlevel = 50\n JOIN mdl_course c ON c.id = ct.instanceid\n AND e.courseid = c.id\n JOIN mdl_role r ON r.id = ra.roleid\n AND r.shortname = 'student'\n WHERE courseid = " . $course->id . "\n AND e.status = 0\n AND u.suspended = 0\n AND u.deleted = 0\n AND (\n ue.timeend = 0\n OR ue.timeend > NOW()\n )\n AND ue.status = 0\n ORDER BY userid ASC;"; if (!($enrollees = $DB->get_records_sql($sql))) { overnight::tlog('No enrolled students found for course ' . $course->id . '.', 'warn'); } else { $num_enrollees = count($enrollees); overnight::tlog('Found ' . $num_enrollees . ' students enrolled onto course ' . $course->id . '.', 'info'); // A variable to store which enrollee we're processing. $cur_enrollees = 0; foreach ($enrollees as $enrollee) { $cur_enrollees++; // Attempt to extract the student ID from the username. $tmp = explode('@', $enrollee->username); $enrollee->studentid = $tmp[0]; // A proper student, hopefully. overnight::tlog('- Processing user (' . $cur_enrollees . '/' . $num_enrollees . ') ' . $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->userid . ') [' . $enrollee->studentid . '] on course ' . $course->id . '.', 'info'); $logging['students_processed'][] = $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->studentid . ') [' . $enrollee->userid . '] on course ' . $course->id . '.'; $logging['students_unique'][$enrollee->userid] = $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->studentid . ') [' . $enrollee->userid . '].'; // Assemble the URL with the correct data. $leapdataurl = sprintf(LEAP_API_URL, $enrollee->studentid); //if ( DEBUG ) { // overnight::tlog('-- Leap URL: ' . $leapdataurl, 'dbug'); //} // Use fopen to read from the API. if (!($handle = fopen($leapdataurl, 'r'))) { // If the API can't be reached for some reason. overnight::tlog('- Cannot open ' . $leapdataurl . '.', 'EROR'); } else { // API reachable, get the data. $leapdata = fgets($handle); fclose($handle); if (DEBUG) { overnight::tlog('-- Returned JSON: ' . $leapdata, 'dbug'); } // Handle an empty result from the API. if (strlen($leapdata) == 0) { overnight::tlog('-- API returned 0 bytes.', 'EROR'); } else { // Decode the JSON into an object. $leapdata = json_decode($leapdata); // Checking for JSON decoding errors, seems only right. if (json_last_error()) { overnight::tlog('-- JSON decoding returned error code ' . json_last_error() . ' for user ' . $enrollee->studentid . '.', 'EROR'); } else { // We have a L3VA score! And possibly GCSE English and maths grades too. //$targets['l3va'] = number_format( $leapdata->person->l3va, DECIMALS ); //$gcse['english'] = $leapdata->person->gcse_english; //$gcse['maths'] = $leapdata->person->gcse_maths; //if ( $targets['l3va'] == '' || !is_numeric( $targets['l3va'] ) || $targets['l3va'] <= 0 ) { // // If the L3VA isn't good. // overnight::tlog('-- L3VA is not good: \'' . $targets['l3va'] . '\'.', 'warn'); // $logging['no_l3va'][$enrollee->userid] = $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->studentid . ') [' . $enrollee->userid . '].'; // //} else { //overnight::tlog('-- ' . $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->userid . ') [' . $enrollee->studentid . '] L3VA score: ' . $targets['l3va'] . '.', 'info'); overnight::tlog('-- ' . $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->userid . ') [' . $enrollee->studentid . '].', 'info'); // If this course is tagged as a GCSE English or maths course, use the grades supplied in the JSON. /* if ( $course->coursetype == 'leapcore_gcse_english' ) { $magtemp = overnight::make_mag( $gcse['english'], $course->coursetype, $course->scalename ); $tagtemp = array( null, null ); } else if ( $course->coursetype == 'leapcore_gcse_maths' ) { $magtemp = overnight::make_mag( $gcse['maths'], $course->coursetype, $course->scalename ); $tagtemp = array( null, null ); } else { // Make the MAG from the L3VA. $magtemp = overnight::make_mag( $targets['l3va'], $course->coursetype, $course->scalename ); // Make the TAG in the same way, setting 'true' at the end for the next grade up. $tagtemp = overnight::make_mag( $targets['l3va'], $course->coursetype, $course->scalename, true ); } $targets['mag'] = $magtemp[0]; $targets['tag'] = $tagtemp[0]; */ /* if ( $course->coursetype == 'leapcore_gcse_english' || $course->coursetype == 'leapcore_gcse_maths' ) { overnight::tlog('--- GCSEs passed through from Leap JSON: MAG: \'' . $targets['mag'] . '\' ['. $magtemp[1] .']. TAG: \'' . $targets['tag'] . '\' ['. $tagtemp[1] .'].', 'info'); } else { overnight::tlog('--- Generated data: MAG: \'' . $targets['mag'] . '\' ['. $magtemp[1] .']. TAG: \'' . $targets['tag'] . '\' ['. $tagtemp[1] .'].', 'info'); } if ( $targets['mag'] == '0' || $targets['mag'] == '1' ) { $logging['poor_grades'][] = 'MAG ' . $targets['mag'] . ' assigned to ' . $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->studentid . ') [' . $enrollee->userid . '] on course ' . $course->id . '.'; } if ( $targets['tag'] == '0' || $targets['tag'] == '1' ) { $logging['poor_grades'][] = 'TAG ' . $targets['tag'] . ' assigned to ' . $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->studentid . ') [' . $enrollee->userid . '] on course ' . $course->id . '.'; } */ // Loop through all settable, updateable grades. foreach ($targets as $target => $score) { // Need the grade_items.id for grade_grades.itemid. $gradeitem = $DB->get_record('grade_items', array('courseid' => $course->id, 'itemname' => strtoupper($target)), 'id, categoryid'); // Check to see if this data already exists in the database, so we can insert or update. $gradegrade = $DB->get_record('grade_grades', array('itemid' => $gradeitem->id, 'userid' => $enrollee->userid), 'id'); // New grade_grade object. $grade = new \grade_grade(); $grade->userid = $enrollee->userid; $grade->itemid = $gradeitem->id; $grade->categoryid = $gradeitem->categoryid; $grade->rawgrade = $score; // Will stay as set. $grade->finalgrade = $score; // Will change with the grade, e.g. 3. $grade->timecreated = time(); $grade->timemodified = $grade->timecreated; // TODO: "excluded" is a thing and prevents a grade being aggregated. $grade->excluded = true; // If no id exists, INSERT. if (!$gradegrade) { if (!($gl = $grade->insert())) { overnight::tlog('--- ' . strtoupper($target) . ' insert failed for user ' . $enrollee->userid . ' on course ' . $course->id . '.', 'EROR'); } else { overnight::tlog('--- ' . strtoupper($target) . ' (' . $score . ') inserted for user ' . $enrollee->userid . ' on course ' . $course->id . '.'); } } else { // If the row already exists, UPDATE, but don't ever *update* the TAG. //if ( $target == 'mag' && !$score ) { // // For MAGs, we don't want to update to a zero or null score as that may overwrite a manually-entered MAG. // overnight::tlog('--- ' . strtoupper( $target ) . ' of 0 or null (' . $score . ') purposefully not updated for user ' . $enrollee->userid . ' on course ' . $course->id . '.' ); // $logging['not_updated'][] = $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->studentid . ') [' . $enrollee->userid . '] on course ' . $course->id . ': ' . strtoupper( $target ) . ' of \'' . $score . '\'.'; //} else if ( $target != 'tag' ) { $grade->id = $gradegrade->id; // We don't want to set this again, but we do want the modified time set. unset($grade->timecreated); $grade->timemodified = time(); if (!($gl = $grade->update())) { overnight::tlog('--- ' . strtoupper($target) . ' update failed for user ' . $enrollee->userid . ' on course ' . $course->id . '.', 'EROR'); } else { overnight::tlog('--- ' . strtoupper($target) . ' (' . $score . ') update for user ' . $enrollee->userid . ' on course ' . $course->id . '.'); } //} else { // overnight::tlog('--- ' . strtoupper( $target ) . ' purposefully not updated for user ' . $enrollee->userid . ' on course ' . $course->id . '.', 'skip' ); // $logging['not_updated'][] = $enrollee->firstname . ' ' . $enrollee->lastname . ' (' . $enrollee->studentid . ') [' . $enrollee->userid . '] on course ' . $course->id . ': ' . strtoupper( $target ) . ' of \'' . $score . '\'.'; //} // END ignore updating the TAG. } // END insert or update check. } // END foreach loop. //} // END L3VA check. } // END any json_decode errors. } // END empty API result. } // END open leap API for reading. } // END cycle through each course enrollee. } // END enrollee query. // Final blank-ish log entry to separate out one course from another. overnight::tlog('', '----'); } // END foreach course tagged 'leapcore_*'. // Sort and dump the summary log. overnight::tlog('Summary of all performed operations.', 'smry'); asort($logging['courses']); asort($logging['students_processed']); asort($logging['students_unique']); asort($logging['no_l3va']); asort($logging['not_updated']); arsort($logging['grade_types']); asort($logging['poor_grades']); // Processing. $logging['num']['courses'] = count($logging['courses']); $logging['num']['students_processed'] = count($logging['students_processed']); $logging['num']['students_unique'] = count($logging['students_unique']); $logging['num']['no_l3va'] = count($logging['no_l3va']); $logging['num']['not_updated'] = count($logging['not_updated']); $logging['num']['grade_types'] = count($logging['grade_types']); foreach ($logging['grade_types'] as $value) { $logging['num']['grade_types_in_use'] += $value; } $logging['num']['poor_grades'] = count($logging['poor_grades']); if ($logging['num']['courses']) { overnight::tlog($logging['num']['courses'] . ' courses:', 'smry'); $count = 0; foreach ($logging['courses'] as $course) { overnight::tlog('- ' . sprintf('%4s', ++$count) . ': ' . $course, 'smry'); } } else { overnight::tlog('No courses processed.', 'warn'); } if ($logging['num']['students_processed']) { overnight::tlog($logging['num']['students_processed'] . ' student-courses processed:', 'smry'); $count = 0; foreach ($logging['students_processed'] as $student) { overnight::tlog('- ' . sprintf('%4s', ++$count) . ': ' . $student, 'smry'); } } else { overnight::tlog('No student-courses processed.', 'warn'); } if ($logging['num']['students_unique']) { overnight::tlog($logging['num']['students_unique'] . ' unique students:', 'smry'); $count = 0; foreach ($logging['students_unique'] as $student) { echo sprintf('%4s', ++$count) . ': ' . $student . "\n"; overnight::tlog('- ' . sprintf('%4s', $count) . ': ' . $student, 'smry'); } } else { overnight::tlog('No unique students processed.', 'warn'); } if ($logging['num']['no_l3va']) { overnight::tlog($logging['num']['no_l3va'] . ' students with no L3VA:', 'smry'); $count = 0; foreach ($logging['no_l3va'] as $no_l3va) { echo sprintf('%4s', ++$count) . ': ' . $no_l3va . "\n"; overnight::tlog('- ' . sprintf('%4s', $count) . ': ' . $no_l3va, 'smry'); } } else { overnight::tlog('No missing L3VAs.', 'warn'); } if ($logging['num']['not_updated']) { overnight::tlog($logging['num']['not_updated'] . ' students purposefully not updated (0 or null grade):', 'smry'); $count = 0; foreach ($logging['not_updated'] as $not_updated) { overnight::tlog('- ' . sprintf('%4s', ++$count) . ': ' . $not_updated, 'smry'); } } else { overnight::tlog('No students purposefully not updated.', 'warn'); } if ($logging['num']['grade_types']) { overnight::tlog($logging['num']['grade_types'] . ' grade types with ' . $logging['num']['grade_types_in_use'] . ' grades set:', 'smry'); $count = 0; foreach ($logging['grade_types'] as $grade_type => $num_grades) { overnight::tlog('- ' . sprintf('%4s', ++$count) . ': ' . $grade_type . ': ' . $num_grades, 'smry'); } } else { overnight::tlog('No grade_types found.', 'warn'); } if ($logging['num']['poor_grades']) { overnight::tlog($logging['num']['poor_grades'] . ' poor grades:', 'smry'); $count = 0; foreach ($logging['poor_grades'] as $poorgrade) { overnight::tlog('- ' . sprintf('%4s', ++$count) . ': ' . $poorgrade, 'smry'); } } else { overnight::tlog('No poor grades found. Good!', 'smry'); } // Finish time. $time_end = microtime(true); $duration = $time_end - $time_start; $mins = floor($duration / 60) == 0 ? '' : floor($duration / 60) . ' minutes'; $secs = $duration % 60 == 0 ? '' : $duration % 60 . ' seconds'; $secs = $mins == '' ? $secs : ' ' . $secs; overnight::tlog('', '----'); overnight::tlog('Finished at ' . date('c', $time_end) . ', took ' . $mins . $secs . ' (' . number_format($duration, DECIMALS) . ' seconds).', 'byby'); //exit(0); return true; echo "\nEND >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"; }
$grade_item->display = 1; // 'Real'. } if ($col_name == 'MAG') { $grade_item->sortorder = 3; //$grade_item->locked = 1; $grade_item->gradetype = $gradeid; $grade_item->scaleid = $scaleid; $grade_item->display = 1; // 'Real'. } // Scale ID, generated earlier. An int, 0 or greater. // TODO: Check if we need this any more!! $grade_item->scale = $scaleid; // Save it all. if (!($gi = $grade_item->insert())) { tlog(' Column \'' . $col_name . '\' could not be inserted for course ' . $course->id . '.', 'EROR'); exit(1); } else { tlog(' Column \'' . $col_name . '\' created for course ' . $course->id . '.'); } } // END skip processing if manual column(s) already found in course. } // END while working through each rquired column. /** * Move the category to the first location in the gradebook if it isn't already. */ //$gtree = new grade_tree($course->id, false, false); //$temp = grade_edit_tree::move_elements(1, '') /**
public function test_force_import_option() { // Need to add users into the system. $user = new stdClass(); $user->firstname = 'Anne'; $user->lastname = 'Able'; $user->email = '*****@*****.**'; $user->id_number = 1; $user1 = $this->getDataGenerator()->create_user($user); $user = new stdClass(); $user->firstname = 'Bobby'; $user->lastname = 'Bunce'; $user->email = '*****@*****.**'; $user->id_number = 2; $user2 = $this->getDataGenerator()->create_user($user); // Create a new grade item. $params = array('itemtype' => 'manual', 'itemname' => 'Grade item 1', 'gradetype' => GRADE_TYPE_VALUE, 'courseid' => $this->courseid); $gradeitem = new grade_item($params, false); $gradeitemid = $gradeitem->insert(); $importcode = 01; $verbosescales = 0; // Form data object. $formdata = new stdClass(); $formdata->mapfrom = 5; $formdata->mapto = 'useremail'; $formdata->mapping_0 = 0; $formdata->mapping_1 = 0; $formdata->mapping_2 = 0; $formdata->mapping_3 = 0; $formdata->mapping_4 = 0; $formdata->mapping_5 = 0; $formdata->mapping_6 = $gradeitemid; $formdata->mapping_7 = 'feedback_2'; $formdata->mapping_8 = 0; $formdata->mapping_9 = 0; $formdata->map = 1; $formdata->id = 2; $formdata->iid = $this->iid; $formdata->importcode = $importcode; $formdata->forceimport = false; // Add last download from this course column to csv content. $exportdate = time(); $newcsvdata = str_replace('{exportdate}', $exportdate, $this->csvtext); $this->csv_load($newcsvdata); $testobject = new phpunit_gradeimport_csv_load_data(); $dataloaded = $testobject->prepare_import_grade_data($this->columns, $formdata, $this->csvimport, $this->courseid, '', '', $verbosescales); $this->assertTrue($dataloaded); // We must update the last modified date. grade_import_commit($this->courseid, $importcode, false, false); // Test using force import disabled and a date in the past. $pastdate = strtotime('-1 day', time()); $newcsvdata = str_replace('{exportdate}', $pastdate, $this->csvtext); $this->csv_load($newcsvdata); $testobject = new phpunit_gradeimport_csv_load_data(); $dataloaded = $testobject->prepare_import_grade_data($this->columns, $formdata, $this->csvimport, $this->courseid, '', '', $verbosescales); $this->assertFalse($dataloaded); $errors = $testobject->get_gradebookerrors(); $this->assertEquals($errors[0], get_string('gradealreadyupdated', 'grades', fullname($user1))); // Test using force import enabled and a date in the past. $formdata->forceimport = true; $testobject = new phpunit_gradeimport_csv_load_data(); $dataloaded = $testobject->prepare_import_grade_data($this->columns, $formdata, $this->csvimport, $this->courseid, '', '', $verbosescales); $this->assertTrue($dataloaded); // Test importing using an old exported file (2 years ago). $formdata->forceimport = false; $twoyearsago = strtotime('-2 year', time()); $newcsvdata = str_replace('{exportdate}', $twoyearsago, $this->csvtext); $this->csv_load($newcsvdata); $testobject = new phpunit_gradeimport_csv_load_data(); $dataloaded = $testobject->prepare_import_grade_data($this->columns, $formdata, $this->csvimport, $this->courseid, '', '', $verbosescales); $this->assertFalse($dataloaded); $errors = $testobject->get_gradebookerrors(); $this->assertEquals($errors[0], get_string('invalidgradeexporteddate', 'grades')); // Test importing using invalid exported date. $baddate = '0123A56B89'; $newcsvdata = str_replace('{exportdate}', $baddate, $this->csvtext); $this->csv_load($newcsvdata); $formdata->mapping_6 = $gradeitemid; $testobject = new phpunit_gradeimport_csv_load_data(); $dataloaded = $testobject->prepare_import_grade_data($this->columns, $formdata, $this->csvimport, $this->courseid, '', '', $verbosescales); $this->assertFalse($dataloaded); $errors = $testobject->get_gradebookerrors(); $this->assertEquals($errors[0], get_string('invalidgradeexporteddate', 'grades')); // Test importing using date in the future. $oneyearahead = strtotime('+1 year', time()); $oldcsv = str_replace('{exportdate}', $oneyearahead, $this->csvtext); $this->csv_load($oldcsv); $formdata->mapping_6 = $gradeitemid; $testobject = new phpunit_gradeimport_csv_load_data(); $dataloaded = $testobject->prepare_import_grade_data($this->columns, $formdata, $this->csvimport, $this->courseid, '', '', $verbosescales); $this->assertFalse($dataloaded); $errors = $testobject->get_gradebookerrors(); $this->assertEquals($errors[0], get_string('invalidgradeexporteddate', 'grades')); }
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); }
} } } if ($exists) { continue; } $grade_item->courseid = $COURSE->id; $grade_item->itemtype = 'mod'; $grade_item->itemmodule = $fromform->modulename; $grade_item->iteminstance = $fromform->instance; $grade_item->itemnumber = $max_itemnumber + 1; $grade_item->itemname = $outcome->fullname; $grade_item->outcomeid = $outcome->id; $grade_item->gradetype = GRADE_TYPE_SCALE; $grade_item->scaleid = $outcome->scaleid; $grade_item->insert(); // TODO comment on these next 4 lines if ($item = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => $grade_item->itemmodule, 'iteminstance' => $grade_item->iteminstance, 'itemnumber' => 0, 'courseid' => $COURSE->id))) { $grade_item->set_parent($item->categoryid); $grade_item->move_after_sortorder($item->sortorder); } $grade_items[] = $grade_item; } } // Create a grade_category to represent this module, if outcomes have been attached if (!empty($grade_items)) { // Add the module's normal grade_item as a child of this category $item_params = array('itemtype' => 'mod', 'itemmodule' => $fromform->modulename, 'iteminstance' => $fromform->instance, 'itemnumber' => 0, 'courseid' => $COURSE->id); $item = grade_item::fetch($item_params); // Only create the category if it will contain at least 2 items if ($item or count($grade_items) > 1) {
/** * Copies the outcomes (and associates to course if necessary) from * a source emarking activity to a destination one * * @param unknown $emarkingsrc * @param unknown $emarkingdst * @return boolean */ function emarking_copy_course_outcomes($emarkingsrc, $emarkingdst) { global $DB, $CFG; require_once $CFG->libdir . "/gradelib.php"; require_once $CFG->libdir . "/grade/grade_outcome.php"; if (!($coursesrc = $DB->get_record('course', array('id' => $emarkingsrc->course)))) { return false; } if (!($coursedst = $DB->get_record('course', array('id' => $emarkingdst->course)))) { return false; } $params = array($coursesrc->id, $emarkingsrc->id); $sql = "SELECT outcomeid, itemnumber\n FROM {grade_items}\n WHERE courseid=? AND outcomeid IS NOT NULL\n AND itemmodule = 'emarking' AND iteminstance = ?\n AND itemtype = 'mod'"; $tocopy = $DB->get_records_sql($sql, $params); $outcomesready = array(); foreach ($tocopy as $outcomeused) { $outcomesready[] = $outcomeused->outcomeid; } $params = array($coursedst->id, $emarkingdst->id); $sql = "SELECT outcomeid, itemnumber\n FROM {grade_items}\n WHERE courseid=? AND outcomeid IS NOT NULL\n AND itemmodule = 'emarking' AND iteminstance = ?\n AND itemtype = 'mod'"; $realused = $DB->get_records_sql($sql, $params); $maxitemnumber = 999; foreach ($realused as $outcomeused) { if (array_search($outcomeused->outcomeid, $outcomesready)) { array_remove_by_value($outcomesready, $outcomeused->outcomeid); } if ($outcomeused->itemnumber > $maxitemnumber) { $maxitemnumber = $outcomeused->itemnumber; } } $outcomesdst = grade_outcome::fetch_all_available($emarkingdst->course); $outcomesavailable = array(); foreach ($outcomesdst as $outcomedst) { $outcomesavailable[] = $outcomedst->id; } if ($maxitemnumber < 1000) { $maxitemnumber = 1000; } foreach ($outcomesready as $outcometocopy) { $outcome = grade_outcome::fetch(array('id' => $outcometocopy)); if (!array_search($outcometocopy, $outcomesavailable)) { $outcome->use_in($emarkingdst->course); } $outcomeitem = new grade_item(); $outcomeitem->courseid = $emarkingdst->course; $outcomeitem->itemtype = 'mod'; $outcomeitem->itemmodule = 'emarking'; $outcomeitem->iteminstance = $emarkingdst->id; $outcomeitem->itemnumber = $maxitemnumber; $outcomeitem->itemname = $outcome->fullname; $outcomeitem->outcomeid = $outcome->id; $outcomeitem->gradetype = GRADE_TYPE_SCALE; $outcomeitem->scaleid = $outcome->scaleid; $outcomeitem->insert(); $maxitemnumber++; } 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; }
/** * Create a Moodle grade item for our test course * * @param string $idnumber The grade item's idnumber * @param int $grademax The max grade (100 if not specified); * @return int Grade item ID */ protected function create_grade_item($idnumber = 'manualitem', $grademax = null) { // Required fields. $data = array('courseid' => 2, 'itemtype' => 'manual', 'idnumber' => $idnumber, 'needsupdate' => false, 'locked' => true); // Optional fields. if ($grademax !== null) { $data['grademax'] = $grademax; } // Save the record. $gradeitem = new \grade_item($data); $gradeitem->insert(); return $gradeitem->id; }
continue 2; } } } $max_itemnumber++; $outcome_item = new grade_item(); $outcome_item->courseid = $course->id; $outcome_item->itemtype = 'mod'; $outcome_item->itemmodule = $fromform->modulename; $outcome_item->iteminstance = $fromform->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($fromform->gradecat)) { $outcome_item->set_parent($fromform->gradecat); } } } } } rebuild_course_cache($course->id); grade_regrade_final_grades($course->id); plagiarism_save_form_elements($fromform);
function RWSUQGrades($r_qiz) { $r_gi = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => $r_qiz->modulename, 'iteminstance' => $r_qiz->instance, 'itemnumber' => 0, 'courseid' => $r_qiz->course)); if ($r_gi && $r_gi->idnumber != $r_qiz->cmidnumber) { $r_gi->idnumber = $r_qiz->cmidnumber; $r_gi->update(); } $r_its = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $r_qiz->modulename, 'iteminstance' => $r_qiz->instance, 'courseid' => $r_qiz->course)); if ($r_its && isset($r_qiz->gradecat)) { if ($r_qiz->gradecat == -1) { $r_gcat = new grade_category(); $r_gcat->courseid = $r_qiz->course; $r_gcat->fullname = $r_qiz->name; $r_gcat->insert(); if ($r_gi) { $r_par = $r_gi->get_parent_category(); $r_gcat->set_parent($r_par->id); } $r_qiz->gradecat = $r_gcat->id; } foreach ($r_its as $r_iti => $r_un) { $r_its[$r_iti]->set_parent($r_qiz->gradecat); if ($r_iti == $r_gi->id) { $r_gi = $r_its[$r_iti]; } } } if ($r_ocs = grade_outcome::fetch_all_available($r_qiz->course)) { $r_gis = array(); $r_mit = 999; if ($r_its) { foreach ($r_its as $r_it) { if ($r_it->itemnumber > $r_mit) { $r_mit = $r_it->itemnumber; } } } foreach ($r_ocs as $r_oc) { $r_eln = 'outcome_' . $r_oc->id; if (property_exists($r_qiz, $r_eln) and $r_qiz->{$r_eln}) { if ($r_its) { foreach ($r_its as $r_it) { if ($r_it->outcomeid == $r_oc->id) { continue 2; } } } $r_mit++; $r_oi = new grade_item(); $r_oi->courseid = $r_qiz->course; $r_oi->itemtype = 'mod'; $r_oi->itemmodule = $r_qiz->modulename; $r_oi->iteminstance = $r_qiz->instance; $r_oi->itemnumber = $r_mit; $r_oi->itemname = $r_oc->fullname; $r_oi->outcomeid = $r_oc->id; $r_oi->gradetype = GRADE_TYPE_SCALE; $r_oi->scaleid = $r_oc->scaleid; $r_oi->insert(); if ($r_gi) { $r_oi->set_parent($r_gi->categoryid); $r_oi->move_after_sortorder($r_gi->sortorder); } else { if (isset($r_qiz->gradecat)) { $r_oi->set_parent($r_qiz->gradecat); } } } } } }
/** * Submit new or update grade; update/create grade_item definition. Grade must have userid specified, * rawgrade and feedback with format are optional. rawgrade NULL means 'Not graded'. * Missing property or key means does not change the existing value. * * Only following grade item properties can be changed 'itemname', 'idnumber', 'gradetype', 'grademax', * 'grademin', 'scaleid', 'multfactor', 'plusfactor', 'deleted' and 'hidden'. 'reset' means delete all current grades including locked ones. * * Manual, course or category items can not be updated by this function. * * @category grade * @param string $source Source of the grade such as 'mod/assignment' * @param int $courseid ID of course * @param string $itemtype Type of grade item. For example, mod or block * @param string $itemmodule More specific then $itemtype. For example, assignment or forum. May be NULL for some item types * @param int $iteminstance Instance ID of graded item * @param int $itemnumber Most probably 0. Modules can use other numbers when having more than one grade for each user * @param mixed $grades Grade (object, array) or several grades (arrays of arrays or objects), NULL if updating grade_item definition only * @param mixed $itemdetails Object or array describing the grading item, NULL if no change * @return int Returns GRADE_UPDATE_OK, GRADE_UPDATE_FAILED, GRADE_UPDATE_MULTIPLE or GRADE_UPDATE_ITEM_LOCKED */ function grade_update($source, $courseid, $itemtype, $itemmodule, $iteminstance, $itemnumber, $grades = NULL, $itemdetails = NULL) { global $USER, $CFG, $DB; // only following grade_item properties can be changed in this function $allowed = array('itemname', 'idnumber', 'gradetype', 'grademax', 'grademin', 'scaleid', 'multfactor', 'plusfactor', 'deleted', 'hidden'); // list of 10,5 numeric fields $floats = array('grademin', 'grademax', 'multfactor', 'plusfactor'); // grade item identification $params = compact('courseid', 'itemtype', 'itemmodule', 'iteminstance', 'itemnumber'); if (is_null($courseid) or is_null($itemtype)) { debugging('Missing courseid or itemtype'); return GRADE_UPDATE_FAILED; } if (!($grade_items = grade_item::fetch_all($params))) { // create a new one $grade_item = false; } else { if (count($grade_items) == 1) { $grade_item = reset($grade_items); unset($grade_items); //release memory } else { debugging('Found more than one grade item'); return GRADE_UPDATE_MULTIPLE; } } if (!empty($itemdetails['deleted'])) { if ($grade_item) { if ($grade_item->delete($source)) { return GRADE_UPDATE_OK; } else { return GRADE_UPDATE_FAILED; } } return GRADE_UPDATE_OK; } /// Create or update the grade_item if needed if (!$grade_item) { if ($itemdetails) { $itemdetails = (array) $itemdetails; // grademin and grademax ignored when scale specified if (array_key_exists('scaleid', $itemdetails)) { if ($itemdetails['scaleid']) { unset($itemdetails['grademin']); unset($itemdetails['grademax']); } } foreach ($itemdetails as $k => $v) { if (!in_array($k, $allowed)) { // ignore it continue; } if ($k == 'gradetype' and $v == GRADE_TYPE_NONE) { // no grade item needed! return GRADE_UPDATE_OK; } $params[$k] = $v; } } $grade_item = new grade_item($params); $grade_item->insert(); } else { if ($grade_item->is_locked()) { // no notice() here, test returned value instead! return GRADE_UPDATE_ITEM_LOCKED; } if ($itemdetails) { $itemdetails = (array) $itemdetails; $update = false; foreach ($itemdetails as $k => $v) { if (!in_array($k, $allowed)) { // ignore it continue; } if (in_array($k, $floats)) { if (grade_floats_different($grade_item->{$k}, $v)) { $grade_item->{$k} = $v; $update = true; } } else { if ($grade_item->{$k} != $v) { $grade_item->{$k} = $v; $update = true; } } } if ($update) { $grade_item->update(); } } } /// reset grades if requested if (!empty($itemdetails['reset'])) { $grade_item->delete_all_grades('reset'); return GRADE_UPDATE_OK; } /// Some extra checks // do we use grading? if ($grade_item->gradetype == GRADE_TYPE_NONE) { return GRADE_UPDATE_OK; } // no grade submitted if (empty($grades)) { return GRADE_UPDATE_OK; } /// Finally start processing of grades if (is_object($grades)) { $grades = array($grades->userid => $grades); } else { if (array_key_exists('userid', $grades)) { $grades = array($grades['userid'] => $grades); } } /// normalize and verify grade array foreach ($grades as $k => $g) { if (!is_array($g)) { $g = (array) $g; $grades[$k] = $g; } if (empty($g['userid']) or $k != $g['userid']) { debugging('Incorrect grade array index, must be user id! Grade ignored.'); unset($grades[$k]); } } if (empty($grades)) { return GRADE_UPDATE_FAILED; } $count = count($grades); if ($count > 0 and $count < 200) { list($uids, $params) = $DB->get_in_or_equal(array_keys($grades), SQL_PARAMS_NAMED, $start = 'uid'); $params['gid'] = $grade_item->id; $sql = "SELECT * FROM {grade_grades} WHERE itemid = :gid AND userid {$uids}"; } else { $sql = "SELECT * FROM {grade_grades} WHERE itemid = :gid"; $params = array('gid' => $grade_item->id); } $rs = $DB->get_recordset_sql($sql, $params); $failed = false; while (count($grades) > 0) { $grade_grade = null; $grade = null; foreach ($rs as $gd) { $userid = $gd->userid; if (!isset($grades[$userid])) { // this grade not requested, continue continue; } // existing grade requested $grade = $grades[$userid]; $grade_grade = new grade_grade($gd, false); unset($grades[$userid]); break; } if (is_null($grade_grade)) { if (count($grades) == 0) { // no more grades to process break; } $grade = reset($grades); $userid = $grade['userid']; $grade_grade = new grade_grade(array('itemid' => $grade_item->id, 'userid' => $userid), false); $grade_grade->load_optional_fields(); // add feedback and info too unset($grades[$userid]); } $rawgrade = false; $feedback = false; $feedbackformat = FORMAT_MOODLE; $usermodified = $USER->id; $datesubmitted = null; $dategraded = null; if (array_key_exists('rawgrade', $grade)) { $rawgrade = $grade['rawgrade']; } if (array_key_exists('feedback', $grade)) { $feedback = $grade['feedback']; } if (array_key_exists('feedbackformat', $grade)) { $feedbackformat = $grade['feedbackformat']; } if (array_key_exists('usermodified', $grade)) { $usermodified = $grade['usermodified']; } if (array_key_exists('datesubmitted', $grade)) { $datesubmitted = $grade['datesubmitted']; } if (array_key_exists('dategraded', $grade)) { $dategraded = $grade['dategraded']; } // update or insert the grade if (!$grade_item->update_raw_grade($userid, $rawgrade, $source, $feedback, $feedbackformat, $usermodified, $dategraded, $datesubmitted, $grade_grade)) { $failed = true; } } if ($rs) { $rs->close(); } if (!$failed) { return GRADE_UPDATE_OK; } else { return GRADE_UPDATE_FAILED; } }
/** * Test get_course_module */ public function test_get_course_module() { global $DB; $this->resetAfterTest(true); $this->setAdminUser(); $course = self::getDataGenerator()->create_course(); $record = array('course' => $course->id, 'name' => 'First Assignment'); $options = array('idnumber' => 'ABC', 'visible' => 0); // Hidden activity. $assign = self::getDataGenerator()->create_module('assign', $record, $options); $outcomescale = 'Distinction, Very Good, Good, Pass, Fail'; // Insert a custom grade scale to be used by an outcome. $gradescale = new grade_scale(); $gradescale->name = 'gettcoursemodulescale'; $gradescale->courseid = $course->id; $gradescale->userid = 0; $gradescale->scale = $outcomescale; $gradescale->description = 'This scale is used to mark standard assignments.'; $gradescale->insert(); // Insert an outcome. $data = new stdClass(); $data->courseid = $course->id; $data->fullname = 'Team work'; $data->shortname = 'Team work'; $data->scaleid = $gradescale->id; $outcome = new grade_outcome($data, false); $outcome->insert(); $outcomegradeitem = new grade_item(); $outcomegradeitem->itemname = $outcome->shortname; $outcomegradeitem->itemtype = 'mod'; $outcomegradeitem->itemmodule = 'assign'; $outcomegradeitem->iteminstance = $assign->id; $outcomegradeitem->outcomeid = $outcome->id; $outcomegradeitem->cmid = 0; $outcomegradeitem->courseid = $course->id; $outcomegradeitem->aggregationcoef = 0; $outcomegradeitem->itemnumber = 1; // The activity's original grade item will be 0. $outcomegradeitem->gradetype = GRADE_TYPE_SCALE; $outcomegradeitem->scaleid = $outcome->scaleid; $outcomegradeitem->insert(); $assignmentgradeitem = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $assign->id, 'itemnumber' => 0, 'courseid' => $course->id)); $outcomegradeitem->set_parent($assignmentgradeitem->categoryid); $outcomegradeitem->move_after_sortorder($assignmentgradeitem->sortorder); // Test admin user can see the complete hidden activity. $result = core_course_external::get_course_module($assign->cmid); $result = external_api::clean_returnvalue(core_course_external::get_course_module_returns(), $result); $this->assertCount(0, $result['warnings']); // Test we retrieve all the fields. $this->assertCount(27, $result['cm']); $this->assertEquals($record['name'], $result['cm']['name']); $this->assertEquals($options['idnumber'], $result['cm']['idnumber']); $this->assertEquals(100, $result['cm']['grade']); $this->assertEquals(0.0, $result['cm']['gradepass']); $this->assertEquals('submissions', $result['cm']['advancedgrading'][0]['area']); $this->assertEmpty($result['cm']['advancedgrading'][0]['method']); $this->assertEquals($outcomescale, $result['cm']['outcomes'][0]['scale']); $student = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); self::getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id); $this->setUser($student); // The user shouldn't be able to see the activity. try { core_course_external::get_course_module($assign->cmid); $this->fail('Exception expected due to invalid permissions.'); } catch (moodle_exception $e) { $this->assertEquals('requireloginerror', $e->errorcode); } // Make module visible. set_coursemodule_visible($assign->cmid, 1); // Test student user. $result = core_course_external::get_course_module($assign->cmid); $result = external_api::clean_returnvalue(core_course_external::get_course_module_returns(), $result); $this->assertCount(0, $result['warnings']); // Test we retrieve only the few files we can see. $this->assertCount(11, $result['cm']); $this->assertEquals($assign->cmid, $result['cm']['id']); $this->assertEquals($course->id, $result['cm']['course']); $this->assertEquals('assign', $result['cm']['modname']); $this->assertEquals($assign->id, $result['cm']['instance']); }
/** * given an import code, commits all entries in buffer tables * (grade_import_value and grade_import_newitem) * If this function is called, we assume that all data collected * up to this point is fine and we can go ahead and commit * @param int courseid - id of the course * @param string importcode - import batch identifier * @param feedback print feedback and continue button * @return bool success */ function grade_import_commit($courseid, $importcode, $importfeedback = true, $verbose = true) { global $CFG, $USER, $DB; $commitstart = time(); // start time in case we need to roll back $newitemids = array(); // array to hold new grade_item ids from grade_import_newitem table, mapping array /// first select distinct new grade_items with this batch $params = array($importcode, $USER->id); if ($newitems = $DB->get_records_sql("SELECT *\n FROM {grade_import_newitem}\n WHERE importcode = ? AND importer=?", $params)) { // instances of the new grade_items created, cached // in case grade_update fails, so that we can remove them $instances = array(); $failed = false; foreach ($newitems as $newitem) { // get all grades with this item if ($grades = $DB->get_records('grade_import_values', array('newgradeitem' => $newitem->id))) { /// create a new grade item for this - must use false as second param! /// TODO: we need some bounds here too $gradeitem = new grade_item(array('courseid' => $courseid, 'itemtype' => 'manual', 'itemname' => $newitem->itemname), false); $gradeitem->insert('import'); $instances[] = $gradeitem; // insert each individual grade to this new grade item foreach ($grades as $grade) { if (!$gradeitem->update_final_grade($grade->userid, $grade->finalgrade, 'import', $grade->feedback, FORMAT_MOODLE)) { $failed = true; break 2; } } } } if ($failed) { foreach ($instances as $instance) { $gradeitem->delete('import'); } import_cleanup($importcode); return false; } } /// then find all existing items if ($gradeitems = $DB->get_records_sql("SELECT DISTINCT (itemid)\n FROM {grade_import_values}\n WHERE importcode = ? AND importer=? AND itemid > 0", array($importcode, $USER->id))) { $modifieditems = array(); foreach ($gradeitems as $itemid => $notused) { if (!($gradeitem = new grade_item(array('id' => $itemid)))) { // not supposed to happen, but just in case import_cleanup($importcode); return false; } // get all grades with this item if ($grades = $DB->get_records('grade_import_values', array('itemid' => $itemid))) { // make the grades array for update_grade foreach ($grades as $grade) { if (!$importfeedback) { $grade->feedback = false; // ignore it } if (!$gradeitem->update_final_grade($grade->userid, $grade->finalgrade, 'import', $grade->feedback)) { $failed = 1; break 2; } } //$itemdetails -> idnumber = $gradeitem->idnumber; $modifieditems[] = $itemid; } if (!empty($failed)) { import_cleanup($importcode); return false; } } } if ($verbose) { notify(get_string('importsuccess', 'grades'), 'notifysuccess'); $unenrolledusers = get_unenrolled_users_in_import($importcode, $courseid); if ($unenrolledusers) { $list = "<ul>\n"; foreach ($unenrolledusers as $u) { $u->fullname = fullname($u); $list .= '<li>' . get_string('usergrade', 'grades', $u) . '</li>'; } $list .= "</ul>\n"; notify(get_string('unenrolledusersinimport', 'grades', $list), 'notifysuccess'); } print_continue($CFG->wwwroot . '/grade/index.php?id=' . $courseid); } // clean up import_cleanup($importcode); return true; }
/** * Load initial test information * * @param string $assignmentname Assignment name * @param int $student1rawgrade Student 1 grade * @param int $student2rawgrade Student 2 grade * @return array Array of vars with test information */ protected function load_test_data($assignmentname, $student1rawgrade, $student2rawgrade) { global $DB; // Adds a course, a teacher, 2 students, an assignment and grades for the students. $course = $this->getDataGenerator()->create_course(); $coursecontext = context_course::instance($course->id); $studentrole = $DB->get_record('role', array('shortname' => 'student')); $student1 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id); $student2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); $teacher = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); $parent = $this->getDataGenerator()->create_user(); $this->setUser($parent); $student1context = context_user::instance($student1->id); // Creates a new role, gives it the capability and gives $USER that role. $parentroleid = $this->assignUserCapability('moodle/grade:viewall', $student1context->id); // Enrol the user in the course using the new role. $this->getDataGenerator()->enrol_user($parent->id, $course->id, $parentroleid); $assignment = $this->getDataGenerator()->create_module('assign', array('name' => $assignmentname, 'course' => $course->id)); $modcontext = get_coursemodule_from_instance('assign', $assignment->id, $course->id); $assignment->cmidnumber = $modcontext->id; $student1grade = array('userid' => $student1->id, 'rawgrade' => $student1rawgrade); $student2grade = array('userid' => $student2->id, 'rawgrade' => $student2rawgrade); $studentgrades = array($student1->id => $student1grade, $student2->id => $student2grade); assign_grade_item_update($assignment, $studentgrades); // Insert a custom grade scale to be used by an outcome. $gradescale = new grade_scale(); $gradescale->name = 'unittestscale3'; $gradescale->courseid = $course->id; $gradescale->userid = 0; $gradescale->scale = 'Distinction, Very Good, Good, Pass, Fail'; $gradescale->description = 'This scale is used to mark standard assignments.'; $gradescale->insert(); // Insert an outcome. $data = new stdClass(); $data->courseid = $course->id; $data->fullname = 'Team work'; $data->shortname = 'Team work'; $data->scaleid = $gradescale->id; $outcome = new grade_outcome($data, false); $outcome->insert(); $outcomegradeitem = new grade_item(); $outcomegradeitem->itemname = $outcome->shortname; $outcomegradeitem->itemtype = 'mod'; $outcomegradeitem->itemmodule = 'assign'; $outcomegradeitem->iteminstance = $assignment->id; $outcomegradeitem->outcomeid = $outcome->id; $outcomegradeitem->cmid = 0; $outcomegradeitem->courseid = $course->id; $outcomegradeitem->aggregationcoef = 0; $outcomegradeitem->itemnumber = 1; // The activity's original grade item will be 0. $outcomegradeitem->gradetype = GRADE_TYPE_SCALE; $outcomegradeitem->scaleid = $outcome->scaleid; // This next two values for testing that returns parameters are correcly formatted. $outcomegradeitem->set_locked(true); $outcomegradeitem->hidden = ''; $outcomegradeitem->insert(); $assignmentgradeitem = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $assignment->id, 'itemnumber' => 0, 'courseid' => $course->id)); $outcomegradeitem->set_parent($assignmentgradeitem->categoryid); $outcomegradeitem->move_after_sortorder($assignmentgradeitem->sortorder); return array($course, $assignment, $student1, $student2, $teacher, $parent); }
protected function process_grade_item($data) { global $DB; $data = (object) $data; $oldid = $data->id; // We'll need these later $oldparentid = $data->categoryid; $courseid = $this->get_courseid(); // make sure top course category exists, all grade items will be associated // to it. Later, if restoring the whole gradebook, categories will be introduced $coursecat = grade_category::fetch_course_category($courseid); $coursecatid = $coursecat->id; // Get the categoryid to be used $idnumber = null; if (!empty($data->idnumber)) { // Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber // Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop) // so the best is to keep the ones already in the gradebook // Potential problem: duplicates if same items are restored more than once. :-( // This needs to be fixed in some way (outcomes & activities with multiple items) // $data->idnumber = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber; // In any case, verify always for uniqueness $sql = "SELECT cm.id\n FROM {course_modules} cm\n WHERE cm.course = :courseid AND\n cm.idnumber = :idnumber AND\n cm.id <> :cmid"; $params = array('courseid' => $courseid, 'idnumber' => $data->idnumber, 'cmid' => $this->task->get_moduleid()); if (!$DB->record_exists_sql($sql, $params) && !$DB->record_exists('grade_items', array('courseid' => $courseid, 'idnumber' => $data->idnumber))) { $idnumber = $data->idnumber; } } unset($data->id); $data->categoryid = $coursecatid; $data->courseid = $this->get_courseid(); $data->iteminstance = $this->task->get_activityid(); $data->idnumber = $idnumber; $data->scaleid = $this->get_mappingid('scale', $data->scaleid); $data->outcomeid = $this->get_mappingid('outcome', $data->outcomeid); $data->timecreated = $this->apply_date_offset($data->timecreated); $data->timemodified = $this->apply_date_offset($data->timemodified); $gradeitem = new grade_item($data, false); $gradeitem->insert('restore'); //sortorder is automatically assigned when inserting. Re-instate the previous sortorder $gradeitem->sortorder = $data->sortorder; $gradeitem->update('restore'); // Set mapping, saving the original category id into parentitemid // gradebook restore (final task) will need it to reorganise items $this->set_mapping('grade_item', $oldid, $gradeitem->id, false, null, $oldparentid); }
/** * Validate that the version 1 plugin deletes appropriate associations when * deleting a course */ public function test_version1importdeletecoursedeletesassociations() { global $DB, $CFG, $USER; require_once $CFG->dirroot . '/user/lib.php'; require_once $CFG->dirroot . '/lib/gradelib.php'; require_once $CFG->dirroot . '/group/lib.php'; require_once $CFG->dirroot . '/lib/conditionlib.php'; require_once $CFG->dirroot . '/lib/enrollib.php'; require_once $CFG->dirroot . '/tag/lib.php'; require_once $CFG->dirroot . '/lib/questionlib.php'; // Setup. $initialnumcontexts = $DB->count_records('context', array('contextlevel' => CONTEXT_COURSE)); $DB->delete_records('block_instances'); // Set up the course with one section, including default blocks. set_config('defaultblocks_topics', 'search_forums'); set_config('maxsections', 10, 'moodlecourse'); $this->run_core_course_import(array('shortname' => 'deleteassociationsshortname', 'numsections' => 1)); // Create a user record. $record = new stdClass(); $record->username = '******'; $record->password = '******'; $userid = user_create_user($record); // Create a course-level role. $courseid = $DB->get_field('course', 'id', array('shortname' => 'deleteassociationsshortname')); $coursecontext = context_course::instance($courseid); $roleid = create_role('deleterole', 'deleterole', 'deleterole'); set_role_contextlevels($roleid, array(CONTEXT_COURSE)); $enrol = new stdClass(); $enrol->enrol = 'manual'; $enrol->courseid = $courseid; $enrol->status = ENROL_INSTANCE_ENABLED; if (!$DB->record_exists('enrol', (array) $enrol)) { $DB->insert_record('enrol', $enrol); } // Assign the user to the course-level role. enrol_try_internal_enrol($courseid, $userid, $roleid); // Create a grade item. $gradeitem = new grade_item(array('courseid' => $courseid, 'itemtype' => 'manual', 'itemname' => 'testitem'), false); $gradeitem->insert(); $gradegrade = new grade_grade(array('itemid' => $gradeitem->id, 'userid' => $userid), false); // Assign the user a grade. $gradegrade->insert(); // Create a grade outcome. $gradeoutcome = new grade_outcome(array('courseid' => $courseid, 'shortname' => 'bogusshortname', 'fullname' => 'bogusfullname')); $gradeoutcome->insert(); // Create a grade scale. $gradescale = new grade_scale(array('courseid' => $courseid, 'name' => 'bogusname', 'userid' => $userid, 'scale' => 'bogusscale', 'description' => 'bogusdescription')); $gradescale->insert(); // Set a grade setting value. grade_set_setting($courseid, 'bogus', 'bogus'); // Set up a grade letter. $gradeletter = new stdClass(); $gradeletter->contextid = $coursecontext->id; $gradeletter->lowerboundary = 80; $gradeletter->letter = 'A'; $DB->insert_record('grade_letters', $gradeletter); // Set up a forum instance. $forum = new stdClass(); $forum->course = $courseid; $forum->intro = 'intro'; $forum->id = $DB->insert_record('forum', $forum); // Add it as a course module. $forum->module = $DB->get_field('modules', 'id', array('name' => 'forum')); $forum->instance = $forum->id; $cmid = add_course_module($forum); // Set up a completion record. $completion = new stdClass(); $completion->coursemoduleid = $cmid; $completion->completionstate = 0; $completion->userid = 9999; $completion->timemodified = time(); $DB->insert_record('course_modules_completion', $completion); // Set up a completion condition. $forum->id = $cmid; $ci = new condition_info($forum, CONDITION_MISSING_EVERYTHING, false); $ci->add_completion_condition($cmid, COMPLETION_ENABLED); // Set the blocks position. $instances = $DB->get_records('block_instances', array('parentcontextid' => $coursecontext->id)); $page = new stdClass(); $page->context = $coursecontext; $page->pagetype = 'course-view-*'; $page->subpage = false; foreach ($instances as $instance) { blocks_set_visibility($instance, $page, 1); } // Create a group. $group = new stdClass(); $group->name = 'testgroup'; $group->courseid = $courseid; $groupid = groups_create_group($group); // Add the user to the group. groups_add_member($groupid, $userid); // Create a grouping containing our group. $grouping = new stdClass(); $grouping->name = 'testgrouping'; $grouping->courseid = $courseid; $groupingid = groups_create_grouping($grouping); groups_assign_grouping($groupingid, $groupid); // Set up a user tag. tag_set('course', $courseid, array('testtag')); // Add a course-level log. add_to_log($courseid, 'bogus', 'bogus'); // Set up the default course question category. $newcategory = question_make_default_categories(array($coursecontext)); // Create a test question. $question = new stdClass(); $question->qtype = 'truefalse'; $form = new stdClass(); $form->category = $newcategory->id; $form->name = 'testquestion'; $form->correctanswer = 1; $form->feedbacktrue = array('text' => 'bogustext', 'format' => FORMAT_HTML); $form->feedbackfalse = array('text' => 'bogustext', 'format' => FORMAT_HTML); $question = question_bank::get_qtype('truefalse')->save_question($question, $form); if (function_exists('course_set_display')) { // Set a "course display" setting. course_set_display($courseid, 1); } // Make a bogus backup record. $backupcourse = new stdClass(); $backupcourse->courseid = $courseid; $DB->insert_record('backup_courses', $backupcourse); // Add a user lastaccess record. $lastaccess = new stdClass(); $lastaccess->userid = $userid; $lastaccess->courseid = $courseid; $DB->insert_record('user_lastaccess', $lastaccess); // Make a bogus backup log record. $log = new stdClass(); $log->backupid = $courseid; $log->timecreated = time(); $log->loglevel = 1; $log->message = 'bogus'; $DB->insert_record('backup_logs', $log); // Get initial counts. $initialnumcourse = $DB->count_records('course'); $initialnumroleassignments = $DB->count_records('role_assignments'); $initialnumuserenrolments = $DB->count_records('user_enrolments'); $initialnumgradeitems = $DB->count_records('grade_items'); $initialnumgradegrades = $DB->count_records('grade_grades'); $initialnumgradeoutcomes = $DB->count_records('grade_outcomes'); $initialnumgradeoutcomescourses = $DB->count_records('grade_outcomes_courses'); $initialnumscale = $DB->count_records('scale'); $initialnumgradesettings = $DB->count_records('grade_settings'); $initialnumgradeletters = $DB->count_records('grade_letters'); $initialnumforum = $DB->count_records('forum'); $initialnumcoursemodules = $DB->count_records('course_modules'); $initialnumcoursemodulescompletion = $DB->count_records('course_modules_completion'); $initialnumcoursemodulesavailability = $DB->count_records('course_modules_availability'); $initialnumblockinstances = $DB->count_records('block_instances'); $initialnumblockpositions = $DB->count_records('block_positions'); $initialnumgroups = $DB->count_records('groups'); $initialnumgroupsmembers = $DB->count_records('groups_members'); $initialnumgroupings = $DB->count_records('groupings'); $initialnumgroupingsgroups = $DB->count_records('groupings_groups'); $initialnumtaginstance = $DB->count_records('tag_instance'); $initialnumcoursesections = $DB->count_records('course_sections'); $initialnumquestioncategories = $DB->count_records('question_categories'); $initialnumquestion = $DB->count_records('question'); if (self::$coursedisplay) { $initialnumcoursedisplay = $DB->count_records('course_display'); } $initialnumbackupcourses = $DB->count_records('backup_courses'); $initialnumuserlastaccess = $DB->count_records('user_lastaccess'); $initialnumbackuplogs = $DB->count_records('backup_logs'); // Delete the course. $data = array('action' => 'delete', 'shortname' => 'deleteassociationsshortname'); $this->run_core_course_import($data, false); // Validate the result. $this->assertEquals($DB->count_records('course'), $initialnumcourse - 1); $this->assertEquals($DB->count_records('role_assignments'), $initialnumroleassignments - 1); $this->assertEquals($DB->count_records('user_enrolments'), $initialnumuserenrolments - 1); $this->assertEquals($DB->count_records('grade_items'), $initialnumgradeitems - 2); $this->assertEquals($DB->count_records('grade_grades'), $initialnumgradegrades - 1); $this->assertEquals($DB->count_records('grade_outcomes'), $initialnumgradeoutcomes - 1); $this->assertEquals($DB->count_records('grade_outcomes_courses'), $initialnumgradeoutcomescourses - 1); $this->assertEquals($DB->count_records('scale'), $initialnumscale - 1); $this->assertEquals($DB->count_records('grade_settings'), $initialnumgradesettings - 1); $this->assertEquals($DB->count_records('grade_letters'), $initialnumgradeletters - 1); $this->assertEquals($DB->count_records('forum'), $initialnumforum - 1); $this->assertEquals($DB->count_records('course_modules'), $initialnumcoursemodules - 1); /* Uncomment the two lines below when this fix is available: http://tracker.moodle.org/browse/MDL-32988 $this->assertEquals($DB->count_records('course_modules_completion'), $initialnumcourse_modules_completion - 1); $this->assertEquals($DB->count_records('course_modules_availability'), $initialnumcourse_modules_availability - 1); */ $this->assertEquals($initialnumblockinstances - 4, $DB->count_records('block_instances')); $this->assertEquals($DB->count_records('block_positions'), 0); $this->assertEquals($DB->count_records('groups'), $initialnumgroups - 1); $this->assertEquals($DB->count_records('groups_members'), $initialnumgroupsmembers - 1); $this->assertEquals($DB->count_records('groupings'), $initialnumgroupings - 1); $this->assertEquals($DB->count_records('groupings_groups'), $initialnumgroupingsgroups - 1); $this->assertEquals($DB->count_records('log', array('course' => $courseid)), 0); $this->assertEquals($DB->count_records('tag_instance'), $initialnumtaginstance - 1); $this->assertEquals($DB->count_records('course_sections'), $initialnumcoursesections - 1); $this->assertEquals($DB->count_records('question_categories'), $initialnumquestioncategories - 1); $this->assertEquals($DB->count_records('question'), $initialnumquestion - 1); if (self::$coursedisplay) { $this->assertEquals($DB->count_records('course_display'), $initialnumcoursedisplay - 1); } $this->assertEquals($DB->count_records('backup_courses'), $initialnumbackupcourses - 1); $this->assertEquals($DB->count_records('user_lastaccess'), $initialnumuserlastaccess - 1); }