/** * Serves assignment submissions and other files. * * @param mixed $course course or id of the course * @param mixed $cm course module or id of the course module * @param context $context * @param string $filearea * @param array $args * @param bool $forcedownload * @return bool false if file not found, does not return if found - just send the file */ function assignsubmission_onenote_pluginfile($course, $cm, context $context, $filearea, $args, $forcedownload) { global $DB, $CFG; if ($context->contextlevel != CONTEXT_MODULE) { return false; } require_login($course, false, $cm); $itemid = (int) array_shift($args); $record = $DB->get_record('assign_submission', array('id' => $itemid), 'userid, assignment, groupid', MUST_EXIST); $userid = $record->userid; $groupid = $record->groupid; require_once $CFG->dirroot . '/mod/assign/locallib.php'; $assign = new assign($context, $cm, $course); if ($assign->get_instance()->id != $record->assignment) { return false; } if ($assign->get_instance()->teamsubmission && !$assign->can_view_group_submission($groupid)) { return false; } if (!$assign->get_instance()->teamsubmission && !$assign->can_view_submission($userid)) { return false; } $relativepath = implode('/', $args); $fullpath = "/{$context->id}/assignsubmission_onenote/{$filearea}/{$itemid}/{$relativepath}"; $fs = get_file_storage(); if (!($file = $fs->get_file_by_hash(sha1($fullpath))) || $file->is_directory()) { return false; } // Download MUST be forced - security! send_stored_file($file, 0, 0, true); }
public function test_grade_edit_tree_column_range_get_item_cell() { global $DB, $CFG; $this->resetAfterTest(true); // Make some things we need. $scale = $this->getDataGenerator()->create_scale(); $course = $this->getDataGenerator()->create_course(); $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); $modulecontext = context_module::instance($assign->id); // The generator returns a dummy object, lets get the real assign object. $assign = new assign($modulecontext, false, false); $cm = $assign->get_course_module(); // Get range column. $column = grade_edit_tree_column::factory('range'); $gradeitemparams = array('itemtype' => 'mod', 'itemmodule' => $cm->modname, 'iteminstance' => $cm->instance, 'courseid' => $cm->course, 'itemnumber' => 0); // Lets set the grade to something we know. $instance = $assign->get_instance(); $instance->grade = 70; $instance->instance = $instance->id; $assign->update_instance($instance); $gradeitem = grade_item::fetch($gradeitemparams); $cell = $column->get_item_cell($gradeitem, array()); $this->assertEquals(GRADE_TYPE_VALUE, $gradeitem->gradetype); $this->assertEquals(null, $gradeitem->scaleid); $this->assertEquals(70.0, (double) $cell->text, "Grade text is 70", 0.01); // Now change it to a scale. $instance = $assign->get_instance(); $instance->grade = -$scale->id; $instance->instance = $instance->id; $assign->update_instance($instance); $gradeitem = grade_item::fetch($gradeitemparams); $cell = $column->get_item_cell($gradeitem, array()); // Make the expected scale text. $scaleitems = null; $scaleitems = explode(',', $scale->scale); $scalestring = end($scaleitems) . ' (' . count($scaleitems) . ')'; $this->assertEquals(GRADE_TYPE_SCALE, $gradeitem->gradetype); $this->assertEquals($scale->id, $gradeitem->scaleid); $this->assertEquals($scalestring, $cell->text, "Grade text matches scale"); // Now change it to no grade. $instance = $assign->get_instance(); $instance->grade = 0; $instance->instance = $instance->id; $assign->update_instance($instance); $gradeitem = grade_item::fetch($gradeitemparams); $cell = $column->get_item_cell($gradeitem, array()); $this->assertEquals(GRADE_TYPE_TEXT, $gradeitem->gradetype); $this->assertEquals(null, $gradeitem->scaleid); $this->assertEquals(' - ', $cell->text, 'Grade text matches empty value of " - "'); }
/** * Permission control method for submission plugin ---- required method for AJAXmoodle based comment API * * @param stdClass $options * @return array */ function assignsubmission_comments_comment_permissions(stdClass $options) { global $USER, $CFG, $DB; if ($options->commentarea != 'submission_comments' && $options->commentarea != 'submission_comments_upgrade') { throw new comment_exception('invalidcommentarea'); } if (!$submission = $DB->get_record('assign_submission', array('id'=>$options->itemid))) { throw new comment_exception('invalidcommentitemid'); } $context = $options->context; require_once($CFG->dirroot . '/mod/assign/locallib.php'); $assignment = new assign($context, null, null); if ($assignment->get_instance()->id != $submission->assignment) { throw new comment_exception('invalidcontext'); } if (!has_capability('mod/assign:grade', $context)) { if (!has_capability('mod/assign:submit', $context)) { return array('post' => false, 'view' => false); } else if ($submission->userid != $USER->id) { return array('post' => false, 'view' => false); } } return array('post' => true, 'view' => true); }
/** * Get a configuration value for this plugin * * @param mixed $setting The config key (string) or null * @return mixed string | false */ public final function get_config($setting = null) { global $DB; if ($setting) { if (!$this->assignment->has_instance()) { return false; } $assignment = $this->assignment->get_instance(); if ($assignment) { $dbparams = array('assignment' => $assignment->id, 'subtype' => $this->get_subtype(), 'plugin' => $this->get_type(), 'name' => $setting); $result = $DB->get_record('assign_plugin_config', $dbparams, '*', IGNORE_MISSING); if ($result) { return $result->value; } } return false; } $dbparams = array('assignment' => $this->assignment->get_instance()->id, 'subtype' => $this->get_subtype(), 'plugin' => $this->get_type()); $results = $DB->get_records('assign_plugin_config', $dbparams); $config = new stdClass(); if (is_array($results)) { foreach ($results as $setting) { $name = $setting->name; $config->{$name} = $setting->value; } } return $config; }
/** * Create instance of event. * * @param \assign $assign * @param \stdClass $submission * @return submission_viewed */ public static function create_from_submission(\assign $assign, \stdClass $submission) { $data = array('objectid' => $submission->id, 'relateduserid' => $submission->userid, 'context' => $assign->get_context(), 'other' => array('assignid' => $assign->get_instance()->id)); /** @var submission_viewed $event */ $event = self::create($data); $event->set_assign($assign); $event->add_record_snapshot('assign_submission', $submission); return $event; }
/** * Create instance of event. * * @param \assign $assign * @return batch_set_marker_allocation_viewed */ public static function create_from_assign(\assign $assign) { $data = array('context' => $assign->get_context(), 'other' => array('assignid' => $assign->get_instance()->id)); self::$preventcreatecall = false; /** @var batch_set_marker_allocation_viewed $event */ $event = self::create($data); self::$preventcreatecall = true; $event->set_assign($assign); return $event; }
/** * Create instance of event. * * @since Moodle 2.7 * * @param \assign $assign * @return all_submissions_downloaded */ public static function create_from_assign(\assign $assign) { $data = array('context' => $assign->get_context(), 'objectid' => $assign->get_instance()->id); self::$preventcreatecall = false; /** @var submission_graded $event */ $event = self::create($data); self::$preventcreatecall = true; $event->set_assign($assign); return $event; }
/** * Always return a valid sort - even if the userid column is missing. * @return array column name => SORT_... constant. */ public function get_sort_columns() { $result = parent::get_sort_columns(); $assignment = $this->assignment->get_instance(); if (empty($assignment->blindmarking)) { $result = array_merge($result, array('userid' => SORT_ASC)); } else { $result = array_merge($result, ['COALESCE(s.timecreated, ' . time() . ')' => SORT_ASC, 'COALESCE(s.id, ' . PHP_INT_MAX . ')' => SORT_ASC, 'um.id' => SORT_ASC]); } return $result; }
/** * Create instance of event. * * @since Moodle 2.7 * * @param \assign $assign * @param \stdClass $user * @return submission_locked */ public static function create_from_user(\assign $assign, \stdClass $user) { $data = array('context' => $assign->get_context(), 'objectid' => $assign->get_instance()->id, 'relateduserid' => $user->id); self::$preventcreatecall = false; /** @var submission_locked $event */ $event = self::create($data); self::$preventcreatecall = true; $event->set_assign($assign); $event->add_record_snapshot('user', $user); return $event; }
static function unplag_reset_file($id) { global $DB, $CFG; $plagiarismfile = $DB->get_record('plagiarism_unplag_files', array('id' => $id), '*', MUST_EXIST); if ($plagiarismfile->statuscode == UNPLAG_STATUSCODE_PROCESSED || $plagiarismfile->statuscode == UNPLAG_STATUSCODE_ACCEPTED) { // Sanity Check. return true; } // Set some new values. $plagiarismfile->statuscode = 'pending'; $plagiarismfile->attempt = 0; $plagiarismfile->timesubmitted = time(); $cm = get_coursemodule_from_id('', $plagiarismfile->cm); $modulecontext = context_module::instance($plagiarismfile->cm); $fs = get_file_storage(); if ($cm->modname == 'assignment') { $submission = $DB->get_record('assignment_submissions', array('assignment' => $cm->instance, 'userid' => $plagiarismfile->userid)); $files = $fs->get_area_files($modulecontext->id, 'mod_assignment', 'submission', $submission->id); foreach ($files as $file) { if ($file->get_contenthash() == $plagiarismfile->identifier) { $DB->update_record('plagiarism_unplag_files', $plagiarismfile); // Update before trying to send again. return self::unplag_send_file($plagiarismfile->cm, $plagiarismfile->userid, $file, self::get_settings()); } } } else { if ($cm->modname == 'assign') { require_once $CFG->dirroot . '/mod/assign/locallib.php'; $assign = new assign($modulecontext, null, null); $submissionplugins = $assign->get_submission_plugins(); $dbparams = array('assignment' => $assign->get_instance()->id, 'userid' => $plagiarismfile->userid); $submissions = $DB->get_records('assign_submission', $dbparams); foreach ($submissions as $submission) { foreach ($submissionplugins as $submissionplugin) { $component = $submissionplugin->get_subtype() . '_' . $submissionplugin->get_type(); $fileareas = $submissionplugin->get_file_areas(); foreach ($fileareas as $filearea => $name) { $files = $fs->get_area_files($assign->get_context()->id, $component, $filearea, $submission->id, "timemodified", false); foreach ($files as $file) { if ($file->get_contenthash() == $plagiarismfile->identifier) { $DB->update_record('plagiarism_unplag_files', $plagiarismfile); // Update before trying to send again. return self::unplag_send_file($plagiarismfile->cm, $plagiarismfile->userid, $file, plagiarism_plugin_unplag::get_settings()); } } } } } } else { if ($cm->modname == 'workshop') { require_once $CFG->dirroot . '/mod/workshop/locallib.php'; $cm = get_coursemodule_from_id('workshop', $plagiarismfile->cm, 0, false, MUST_EXIST); $workshop = $DB->get_record('workshop', array('id' => $cm->instance), '*', MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); $workshop = new workshop($workshop, $cm, $course); $submissions = $workshop->get_submissions($plagiarismfile->userid); foreach ($submissions as $submission) { $files = $fs->get_area_files($workshop->context->id, 'mod_workshop', 'submission_attachment', $submission->id); foreach ($files as $file) { if ($file->get_contenthash() == $plagiarismfile->identifier) { $DB->update_record('plagiarism_unplag_files', $plagiarismfile); // Update before trying to send again. return self::unplag_send_file($plagiarismfile->cm, $plagiarismfile->userid, $file, plagiarism_plugin_unplag::get_settings()); } } } } else { if ($cm->modname == 'forum') { require_once $CFG->dirroot . '/mod/forum/lib.php'; $cm = get_coursemodule_from_id('forum', $plagiarismfile->cm, 0, false, MUST_EXIST); $posts = forum_get_user_posts($cm->instance, $plagiarismfile->userid); foreach ($posts as $post) { $files = $fs->get_area_files($modulecontext->id, 'mod_forum', 'attachment', $post->id, "timemodified", false); foreach ($files as $file) { if ($file->get_contenthash() == $plagiarismfile->identifier) { $DB->update_record('plagiarism_unplag_files', $plagiarismfile); // Update before trying to send again. return self::unplag_send_file($plagiarismfile->cm, $plagiarismfile->userid, $file, plagiarism_plugin_unplag::get_settings()); } } } } } } } }
public function test_list_participants_blind_marking() { global $DB; $this->resetAfterTest(true); $course = $this->getDataGenerator()->create_course(); $roles = $DB->get_records('role', null, '', 'shortname, id'); $teacher = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $roles['teacher']->id); $this->setUser($teacher); // Enrol two students. $students = []; for ($i = 0; $i < 2; $i++) { $student = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($student->id, $course->id, $roles['student']->id); $students[$student->id] = $student; } $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $instance = $generator->create_instance(['course' => $course->id, 'blindmarking' => 1]); $cm = get_coursemodule_from_instance('assign', $instance->id); $context = context_module::instance($cm->id); $assign = new assign($context, $cm, $course); // Allocate IDs now. // We're testing whether the IDs are correct after allocation. assign::allocate_unique_ids($assign->get_instance()->id); $participants = $assign->list_participants(null, false); // There should be exactly two participants and they should be the students. $this->assertCount(2, $participants); foreach ($participants as $participant) { $this->assertArrayHasKey($participant->id, $students); } $keys = array_keys($participants); // Create a grading table, and query the DB This should have the same order. $table = new assign_grading_table($assign, 10, '', 0, false); $table->setup(); $table->query_db(10); $this->assertEquals($keys, array_keys($table->rawdata)); // Submit a file for the second student. $data = new stdClass(); $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(), 'text' => 'Submission text', 'format' => FORMAT_MOODLE); static::helper_add_submission($assign, $participants[$keys[1]], $data, 'onlinetext'); // Assign has a private cache. The easiest way to clear this is to create a new instance. $assign = new assign($context, $cm, $course); $newparticipants = $assign->list_participants(null, false); // There should be exactly two participants and they should be the students. $this->assertCount(2, $newparticipants); foreach ($newparticipants as $participant) { $this->assertArrayHasKey($participant->id, $students); } $newkeys = array_keys($newparticipants); // The user who submitted first should now be listed first. $this->assertEquals($participants[$keys[1]]->id, $newparticipants[$newkeys[0]]->id); $this->assertEquals($participants[$keys[0]]->id, $newparticipants[$newkeys[1]]->id); // Submit for the other student. static::helper_add_submission($assign, $participants[$keys[0]], $data, 'onlinetext'); $assign = new assign($context, $cm, $course); $newparticipants = $assign->list_participants(null, false); // The users should still be listed in order of the first submission $this->assertEquals($participants[$keys[1]]->id, $newparticipants[$newkeys[0]]->id); $this->assertEquals($participants[$keys[0]]->id, $newparticipants[$newkeys[1]]->id); // The updated grading table should have the same order as the updated participant list. $table->query_db(10); $this->assertEquals($newkeys, array_keys($table->rawdata)); }
/** * View a summary listing of all assignments in the current course. * * @return string */ private function view_course_index() { global $USER; $o = ''; $course = $this->get_course(); $strplural = get_string('modulenameplural', 'assign'); if (!$cms = get_coursemodules_in_course('assign', $course->id, 'm.duedate')) { $o .= $this->get_renderer()->notification(get_string('thereareno', 'moodle', $strplural)); $o .= $this->get_renderer()->continue_button(new moodle_url('/course/view.php', array('id' => $course->id))); return $o; } $strsectionname = ''; $usesections = course_format_uses_sections($course->format); $modinfo = get_fast_modinfo($course); if ($usesections) { $strsectionname = get_string('sectionname', 'format_'.$course->format); $sections = $modinfo->get_section_info_all(); } $courseindexsummary = new assign_course_index_summary($usesections, $strsectionname); $timenow = time(); $currentsection = ''; foreach ($modinfo->instances['assign'] as $cm) { if (!$cm->uservisible) { continue; } $timedue = $cms[$cm->id]->duedate; $sectionname = ''; if ($usesections && $cm->sectionnum) { $sectionname = get_section_name($course, $sections[$cm->sectionnum]); } $submitted = ''; $context = context_module::instance($cm->id); $assignment = new assign($context, $cm, $course); // Apply overrides. $assignment->update_effective_access($USER->id); $timedue = $assignment->get_instance()->duedate; if (has_capability('mod/assign:grade', $context)) { $submitted = $assignment->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED); } else if (has_capability('mod/assign:submit', $context)) { $usersubmission = $assignment->get_user_submission($USER->id, false); if (!empty($usersubmission->status)) { $submitted = get_string('submissionstatus_' . $usersubmission->status, 'assign'); } else { $submitted = get_string('submissionstatus_', 'assign'); } } $gradinginfo = grade_get_grades($course->id, 'mod', 'assign', $cm->instance, $USER->id); if (isset($gradinginfo->items[0]->grades[$USER->id]) && !$gradinginfo->items[0]->grades[$USER->id]->hidden ) { $grade = $gradinginfo->items[0]->grades[$USER->id]->str_grade; } else { $grade = '-'; } $courseindexsummary->add_assign_info($cm->id, $cm->get_formatted_name(), $sectionname, $timedue, $submitted, $grade); } $o .= $this->get_renderer()->render($courseindexsummary); $o .= $this->view_footer(); return $o; }
/** * Callback called by comment::get_comments() and comment::add(). Gives an opportunity to enforce blind-marking. * * @param array $comments * @param stdClass $options * @return array * @throws comment_exception */ function assignsubmission_comments_comment_display($comments, $options) { global $CFG, $DB, $USER; if ($options->commentarea != 'submission_comments' && $options->commentarea != 'submission_comments_upgrade') { throw new comment_exception('invalidcommentarea'); } if (!($submission = $DB->get_record('assign_submission', array('id' => $options->itemid)))) { throw new comment_exception('invalidcommentitemid'); } $context = $options->context; $cm = $options->cm; $course = $options->courseid; require_once $CFG->dirroot . '/mod/assign/locallib.php'; $assignment = new assign($context, $cm, $course); if ($assignment->get_instance()->id != $submission->assignment) { throw new comment_exception('invalidcontext'); } if ($assignment->is_blind_marking() && !empty($comments)) { // Blind marking is being used, may need to map unique anonymous ids to the comments. $usermappings = array(); $hiddenuserstr = trim(get_string('hiddenuser', 'assign')); $guestuser = guest_user(); foreach ($comments as $comment) { // Anonymize the comments. if (empty($usermappings[$comment->userid])) { // The blind-marking information for this commenter has not been generated; do so now. $anonid = $assignment->get_uniqueid_for_user($comment->userid); $commenter = new stdClass(); $commenter->firstname = $hiddenuserstr; $commenter->lastname = $anonid; $commenter->picture = 0; $commenter->id = $guestuser->id; $commenter->email = $guestuser->email; $commenter->imagealt = $guestuser->imagealt; // Temporarily store blind-marking information for use in later comments if necessary. $usermappings[$comment->userid]->fullname = fullname($commenter); $usermappings[$comment->userid]->avatar = $assignment->get_renderer()->user_picture($commenter, array('size' => 18, 'link' => false)); } // Set blind-marking information for this comment. $comment->fullname = $usermappings[$comment->userid]->fullname; $comment->avatar = $usermappings[$comment->userid]->avatar; $comment->profileurl = null; } } return $comments; }
/** * Generic handler function for all events - triggers sending of files. * @return boolean */ public function event_handler($eventdata) { global $DB, $CFG; $supportedevents = urkund_supported_events(); if (!in_array($eventdata->eventtype, $supportedevents)) { return true; // Don't need to handle this event. } $plagiarismsettings = $this->get_settings(); if (!$plagiarismsettings) { return true; } $cmid = !empty($eventdata->cm->id) ? $eventdata->cm->id : $eventdata->cmid; $plagiarismvalues = $DB->get_records_menu('plagiarism_urkund_config', array('cm' => $cmid), '', 'name, value'); if (empty($plagiarismvalues['use_urkund'])) { // Urkund not in use for this cm - return. return true; } // Check if the module associated with this event still exists. if (!$DB->record_exists('course_modules', array('id' => $eventdata->cmid))) { return true; } if ($eventdata->eventtype == 'files_done' || $eventdata->eventtype == 'content_done' || $eventdata->eventtype == 'assessable_submitted' && $eventdata->params['submission_editable'] == false) { // Assignment-specific functionality: // This is a 'finalize' event. No files from this event itself, // but need to check if files from previous events need to be submitted for processing. mtrace("finalise"); $result = true; if (isset($plagiarismvalues['urkund_draft_submit']) && $plagiarismvalues['urkund_draft_submit'] == PLAGIARISM_URKUND_DRAFTSUBMIT_FINAL) { // Any files attached to previous events were not submitted. // These files are now finalized, and should be submitted for processing. if ($eventdata->modulename == 'assignment') { // Hack to include filelib so that file_storage class is available. require_once "{$CFG->dirroot}/mod/assignment/lib.php"; // We need to get a list of files attached to this assignment and put them in an array, so that // we can submit each of them for processing. $assignmentbase = new assignment_base($cmid); $submission = $assignmentbase->get_submission($eventdata->userid); $modulecontext = context_module::instance($eventdata->cmid); $fs = get_file_storage(); if ($files = $fs->get_area_files($modulecontext->id, 'mod_assignment', 'submission', $submission->id, "timemodified", false)) { foreach ($files as $file) { $sendresult = urkund_send_file($cmid, $eventdata->userid, $file, $plagiarismsettings); $result = $result && $sendresult; } } } else { if ($eventdata->modulename == 'assign') { require_once "{$CFG->dirroot}/mod/assign/locallib.php"; require_once "{$CFG->dirroot}/mod/assign/submission/file/locallib.php"; $modulecontext = context_module::instance($eventdata->cmid); $fs = get_file_storage(); if ($files = $fs->get_area_files($modulecontext->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $eventdata->itemid, "id", false)) { foreach ($files as $file) { $sendresult = urkund_send_file($cmid, $eventdata->userid, $file, $plagiarismsettings); $result = $result && $sendresult; } } $submission = $DB->get_record('assignsubmission_onlinetext', array('submission' => $eventdata->itemid)); if (!empty($submission)) { $eventdata->content = trim(format_text($submission->onlinetext, $submission->onlineformat, array('context' => $modulecontext))); $file = urkund_create_temp_file($cmid, $eventdata); $sendresult = urkund_send_file($cmid, $eventdata->userid, $file, $plagiarismsettings); $result = $result && $sendresult; unlink($file->filepath); // Delete temp file. } } } } return $result; } if (isset($plagiarismvalues['urkund_draft_submit']) && $plagiarismvalues['urkund_draft_submit'] == PLAGIARISM_URKUND_DRAFTSUBMIT_FINAL) { // Assignment-specific functionality: // Files should only be sent for checking once "finalized". return true; } // Text is attached. $result = true; if (!empty($eventdata->content)) { $file = urkund_create_temp_file($cmid, $eventdata); $sendresult = urkund_send_file($cmid, $eventdata->userid, $file, $plagiarismsettings); $result = $result && $sendresult; unlink($file->filepath); // Delete temp file. } // Normal situation: 1 or more assessable files attached to event, ready to be checked. if (!empty($eventdata->pathnamehashes)) { foreach ($eventdata->pathnamehashes as $hash) { $fs = get_file_storage(); $efile = $fs->get_file_by_hash($hash); if (empty($efile)) { mtrace("nofilefound!"); continue; } else { if ($efile->get_filename() === '.') { // This 'file' is actually a directory - nothing to submit. continue; } } // Check if assign group submission is being used. if ($eventdata->modulename == 'assign') { require_once "{$CFG->dirroot}/mod/assign/locallib.php"; $modulecontext = context_module::instance($eventdata->cmid); $assign = new assign($modulecontext, false, false); if (!empty($assign->get_instance()->teamsubmission)) { $mygroups = groups_get_user_groups($assign->get_course()->id, $eventdata->userid); if (count($mygroups) == 1) { $groupid = reset($mygroups)[0]; // Only users with single groups are supported - otherwise just use the normal userid on this record. // Get all users from this group. $userids = array(); $users = groups_get_members($groupid, 'u.id'); foreach ($users as $u) { $userids[] = $u->id; } // Find the earliest plagiarism record for this cm with any of these users. $sql = 'cm = ? AND userid IN (' . implode(',', $userids) . ')'; $previousfiles = $DB->get_records_select('plagiarism_urkund_files', $sql, array($eventdata->cmid), 'id'); $sanitycheckusers = 10; // Search through this number of users to find a valid previous submission. $i = 0; foreach ($previousfiles as $pf) { if ($pf->userid == $eventdata->userid) { break; // The submission comes from this user so break. } // Sanity Check to make sure the user isn't in multiple groups. $pfgroups = groups_get_user_groups($assign->get_course()->id, $pf->userid); if (count($pfgroups) == 1) { // This user made the first valid submission so use their id when sending the file. $eventdata->userid = $pf->userid; break; } if ($i >= $sanitycheckusers) { // don't cause a massive loop here and break at a sensible limit. break; } $i++; } } } } $sendresult = urkund_send_file($cmid, $eventdata->userid, $efile, $plagiarismsettings); $result = $result && $sendresult; } } return $result; }
function plagiarism_urkund_check_group($plagiarismfile) { global $DB, $CFG; require_once "{$CFG->dirroot}/mod/assign/locallib.php"; $modulecontext = context_module::instance($plagiarismfile->cm); $assign = new assign($modulecontext, false, false); if (!empty($assign->get_instance()->teamsubmission)) { mtrace("URKUND fileid:" . $plagiarismfile->id . " Group submission detected."); $mygroups = groups_get_user_groups($assign->get_course()->id, $plagiarismfile->userid); if (count($mygroups) == 1) { $groupid = reset($mygroups)[0]; // Only users with single groups are supported - otherwise just use the normal userid on this record. // Get all users from this group. $userids = array(); $users = groups_get_members($groupid, 'u.id'); foreach ($users as $u) { $userids[] = $u->id; } if (!empty($userids)) { // Find the earliest plagiarism record for this cm with any of these users. $sql = 'cm = ? AND userid IN (' . implode(',', $userids) . ')'; $previousfiles = $DB->get_records_select('plagiarism_urkund_files', $sql, array($plagiarismfile->cm), 'id'); $sanitycheckusers = 10; // Search through this number of users to find a valid previous submission. $i = 0; foreach ($previousfiles as $pf) { if ($pf->userid == $plagiarismfile->userid) { return $plagiarismfile; } // Sanity Check to make sure the user isn't in multiple groups. $pfgroups = groups_get_user_groups($assign->get_course()->id, $pf->userid); if (count($pfgroups) == 1) { // This user made the first valid submission so use their id when sending the file. $plagiarismfile->userid = $pf->userid; mtrace("URKUND: Group submission by newuser, modify to use original userid:" . $pf->userid . " id:" . $plagiarismfile->id); return $plagiarismfile; } if ($i >= $sanitycheckusers) { // Don't cause a massive loop here and break at a sensible limit. return $plagiarismfile; } $i++; } } } } return $plagiarismfile; }
/** * This function converts all of the base settings for an instance of * the old assignment to the new format. Then it calls each of the plugins * to see if they can help upgrade this assignment. * @param int $oldassignmentid (don't rely on the old assignment type even being installed) * @param string $log This string gets appended to during the conversion process * @return bool true or false */ public function upgrade_assignment($oldassignmentid, &$log) { // steps to upgrade an assignment global $DB, $CFG, $USER; // steps to upgrade an assignment // is the user the admin? admin check goes here if (!is_siteadmin($USER->id)) { return false; } // should we use a shutdown handler to rollback on timeout? @set_time_limit(ASSIGN_MAX_UPGRADE_TIME_SECS); // get the module details $oldmodule = $DB->get_record('modules', array('name' => 'assignment'), '*', MUST_EXIST); $oldcoursemodule = $DB->get_record('course_modules', array('module' => $oldmodule->id, 'instance' => $oldassignmentid), '*', MUST_EXIST); $oldcontext = context_module::instance($oldcoursemodule->id); // first insert an assign instance to get the id $oldassignment = $DB->get_record('assignment', array('id' => $oldassignmentid), '*', MUST_EXIST); $oldversion = get_config('assignment_' . $oldassignment->assignmenttype, 'version'); $data = new stdClass(); $data->course = $oldassignment->course; $data->name = $oldassignment->name; $data->intro = $oldassignment->intro; $data->introformat = $oldassignment->introformat; $data->alwaysshowdescription = 1; $data->sendnotifications = $oldassignment->emailteachers; $data->sendlatenotifications = $oldassignment->emailteachers; $data->duedate = $oldassignment->timedue; $data->allowsubmissionsfromdate = $oldassignment->timeavailable; $data->grade = $oldassignment->grade; $data->submissiondrafts = $oldassignment->resubmit; $data->preventlatesubmissions = $oldassignment->preventlate; $newassignment = new assign(null, null, null); if (!$newassignment->add_instance($data, false)) { $log = get_string('couldnotcreatenewassignmentinstance', 'mod_assign'); return false; } // now create a new coursemodule from the old one $newmodule = $DB->get_record('modules', array('name' => 'assign'), '*', MUST_EXIST); $newcoursemodule = $this->duplicate_course_module($oldcoursemodule, $newmodule->id, $newassignment->get_instance()->id); if (!$newcoursemodule) { $log = get_string('couldnotcreatenewcoursemodule', 'mod_assign'); return false; } // convert the base database tables (assignment, submission, grade) // these are used to store information in case a rollback is required $gradingarea = null; $gradingdefinitions = null; $gradeidmap = array(); $completiondone = false; $gradesdone = false; // from this point we want to rollback on failure $rollback = false; try { $newassignment->set_context(context_module::instance($newcoursemodule->id)); // the course module has now been created - time to update the core tables // copy intro files $newassignment->copy_area_files_for_upgrade($oldcontext->id, 'mod_assignment', 'intro', 0, $newassignment->get_context()->id, 'mod_assign', 'intro', 0); // get the plugins to do their bit foreach ($newassignment->get_submission_plugins() as $plugin) { if ($plugin->can_upgrade($oldassignment->assignmenttype, $oldversion)) { $plugin->enable(); if (!$plugin->upgrade_settings($oldcontext, $oldassignment, $log)) { $rollback = true; } } else { $plugin->disable(); } } foreach ($newassignment->get_feedback_plugins() as $plugin) { if ($plugin->can_upgrade($oldassignment->assignmenttype, $oldversion)) { $plugin->enable(); if (!$plugin->upgrade_settings($oldcontext, $oldassignment, $log)) { $rollback = true; } } else { $plugin->disable(); } } // see if there is advanced grading upgrades required $gradingarea = $DB->get_record('grading_areas', array('contextid' => $oldcontext->id, 'areaname' => 'submission'), '*', IGNORE_MISSING); if ($gradingarea) { $DB->update_record('grading_areas', array('id' => $gradingarea->id, 'contextid' => $newassignment->get_context()->id, 'component' => 'mod_assign', 'areaname' => 'submissions')); $gradingdefinitions = $DB->get_records('grading_definitions', array('areaid' => $gradingarea->id)); } // upgrade completion data $DB->set_field('course_modules_completion', 'coursemoduleid', $newcoursemodule->id, array('coursemoduleid' => $oldcoursemodule->id)); $allcriteria = $DB->get_records('course_completion_criteria', array('moduleinstance' => $oldcoursemodule->id)); foreach ($allcriteria as $criteria) { $criteria->module = 'assign'; $criteria->moduleinstance = $newcoursemodule->id; $DB->update_record('course_completion_criteria', $criteria); } $completiondone = true; // Migrate log entries so we don't lose them. $logparams = array('cmid' => $oldcoursemodule->id, 'course' => $oldcoursemodule->course); $DB->set_field('log', 'module', 'assign', $logparams); $DB->set_field('log', 'cmid', $newcoursemodule->id, $logparams); // copy all the submission data (and get plugins to do their bit) $oldsubmissions = $DB->get_records('assignment_submissions', array('assignment' => $oldassignmentid)); foreach ($oldsubmissions as $oldsubmission) { $submission = new stdClass(); $submission->assignment = $newassignment->get_instance()->id; $submission->userid = $oldsubmission->userid; $submission->timecreated = $oldsubmission->timecreated; $submission->timemodified = $oldsubmission->timemodified; $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED; $submission->id = $DB->insert_record('assign_submission', $submission); if (!$submission->id) { $log .= get_string('couldnotinsertsubmission', 'mod_assign', $submission->userid); $rollback = true; } foreach ($newassignment->get_submission_plugins() as $plugin) { if ($plugin->can_upgrade($oldassignment->assignmenttype, $oldversion)) { if (!$plugin->upgrade($oldcontext, $oldassignment, $oldsubmission, $submission, $log)) { $rollback = true; } } } if ($oldsubmission->timemarked) { // submission has been graded - create a grade record $grade = new stdClass(); $grade->assignment = $newassignment->get_instance()->id; $grade->userid = $oldsubmission->userid; $grade->grader = $oldsubmission->teacher; $grade->timemodified = $oldsubmission->timemarked; $grade->timecreated = $oldsubmission->timecreated; // $grade->locked = $oldsubmission->locked; $grade->grade = $oldsubmission->grade; $grade->mailed = $oldsubmission->mailed; $grade->id = $DB->insert_record('assign_grades', $grade); if (!$grade->id) { $log .= get_string('couldnotinsertgrade', 'mod_assign', $grade->userid); $rollback = true; } // copy any grading instances if ($gradingarea) { $gradeidmap[$grade->id] = $oldsubmission->id; foreach ($gradingdefinitions as $definition) { $DB->set_field('grading_instances', 'itemid', $grade->id, array('definitionid' => $definition->id, 'itemid' => $oldsubmission->id)); } } foreach ($newassignment->get_feedback_plugins() as $plugin) { if ($plugin->can_upgrade($oldassignment->assignmenttype, $oldversion)) { if (!$plugin->upgrade($oldcontext, $oldassignment, $oldsubmission, $grade, $log)) { $rollback = true; } } } } } $newassignment->update_calendar($newcoursemodule->id); // Reassociate grade_items from the old assignment instance to the new assign instance. // This includes outcome linked grade_items. $params = array('assign', $newassignment->get_instance()->id, 'assignment', $oldassignment->id); $sql = 'UPDATE {grade_items} SET itemmodule = ?, iteminstance = ? WHERE itemmodule = ? AND iteminstance = ?'; $DB->execute($sql, $params); $gradesdone = true; } catch (Exception $exception) { $rollback = true; $log .= get_string('conversionexception', 'mod_assign', $exception->error); } if ($rollback) { // roll back the grades changes if ($gradesdone) { // Reassociate grade_items from the new assign instance to the old assignment instance. $params = array('assignment', $oldassignment->id, 'assign', $newassignment->get_instance()->id); $sql = 'UPDATE {grade_items} SET itemmodule = ?, iteminstance = ? WHERE itemmodule = ? AND iteminstance = ?'; $DB->execute($sql, $params); } // roll back the completion changes if ($completiondone) { $DB->set_field('course_modules_completion', 'coursemoduleid', $oldcoursemodule->id, array('coursemoduleid' => $newcoursemodule->id)); $allcriteria = $DB->get_records('course_completion_criteria', array('moduleinstance' => $newcoursemodule->id)); foreach ($allcriteria as $criteria) { $criteria->module = 'assignment'; $criteria->moduleinstance = $oldcoursemodule->id; $DB->update_record('course_completion_criteria', $criteria); } } // Roll back the log changes $logparams = array('cmid' => $newcoursemodule->id, 'course' => $newcoursemodule->course); $DB->set_field('log', 'module', 'assignment', $logparams); $DB->set_field('log', 'cmid', $oldcoursemodule->id, $logparams); // roll back the advanced grading update if ($gradingarea) { foreach ($gradeidmap as $newgradeid => $oldsubmissionid) { foreach ($gradingdefinitions as $definition) { $DB->set_field('grading_instances', 'itemid', $oldsubmissionid, array('definitionid' => $definition->id, 'itemid' => $newgradeid)); } } $DB->update_record('grading_areas', array('id' => $gradingarea->id, 'contextid' => $oldcontext->id, 'component' => 'mod_assignment', 'areaname' => 'submission')); } $newassignment->delete_instance(); return false; } // all is well, // delete the old assignment (use object delete) $cm = get_coursemodule_from_id('', $oldcoursemodule->id, $oldcoursemodule->course); if ($cm) { $this->delete_course_module($cm); } rebuild_course_cache($oldcoursemodule->course); return true; }
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once dirname(__FILE__) . '/../../../../config.php'; global $CFG, $DB, $PAGE, $USER; require_once $CFG->dirroot . '/mod/assign/locallib.php'; require_once $CFG->dirroot . '/mod/assign/submission/pdf/lib.php'; $id = required_param('id', PARAM_INT); $submissionid = optional_param('submissionid', 0, PARAM_INT); $pageno = optional_param('pageno', 1, PARAM_INT); $url = new moodle_url('/mod/assign/feedback/pdf/viewcomment.php', array('submissionid' => $submissionid, 'pageno' => $pageno, 'id' => $id)); $cm = get_coursemodule_from_id('assign', $id, 0, false, MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); $PAGE->set_url($url); require_login($course, false, $cm); $context = context_module::instance($cm->id); $assignment = new assign($context, $cm, $course); $feedbackpdf = new assign_feedback_pdf($assignment, 'feedback_pdf'); // Check the user has the relevant capability to access this assignment submission. if ($submissionid) { $submission = $DB->get_record('assign_submission', array('id' => $submissionid), '*', MUST_EXIST); } else { if ($assignment->get_instance()->teamsubmission) { $submission = $assignment->get_group_submission($USER->id, 0, false); } else { $submission = $assignment->get_user_submission($USER->id, false); } } if (!$submission) { print_error('nosubmission', 'assignfeedback_pdf'); } $feedbackpdf->edit_comment_page($submission->id, $pageno, false);
/** * The constructor * * @param context $context * @param int $sid * @param string $filearea * @param string $component */ public function __construct(context $context, $sid, $filearea, $component) { global $CFG; $this->context = $context; list($context, $course, $cm) = get_context_info_array($context->id); $this->cm = $cm; $this->course = $course; $fs = get_file_storage(); $this->dir = $fs->get_area_tree($this->context->id, $component, $filearea, $sid); $files = $fs->get_area_files($this->context->id, $component, $filearea, $sid, "timemodified", false); if (!empty($CFG->enableportfolios)) { require_once $CFG->libdir . '/portfoliolib.php'; if (count($files) >= 1 && has_capability('mod/assign:exportownsubmission', $this->context)) { $button = new portfolio_add_button(); $button->set_callback_options('assign_portfolio_caller', array('cmid' => $this->cm->id, 'sid' => $sid, 'area' => $filearea, 'component' => $component), '/mod/assign/portfolio_callback.php'); $button->reset_formats(); $this->portfolioform = $button->to_html(PORTFOLIO_ADD_TEXT_LINK); } } // plagiarism check if it is enabled $output = ''; if (!empty($CFG->enableplagiarism)) { require_once $CFG->libdir . '/plagiarismlib.php'; // for plagiarism_get_links $assignment = new assign($this->context, null, null); foreach ($files as $file) { $output .= plagiarism_get_links(array('userid' => $sid, 'file' => $file, 'cmid' => $this->cm->id, 'course' => $this->course, 'assignment' => $assignment->get_instance())); $output .= '<br />'; } } $this->preprocess($this->dir, $filearea, $component); }
/** * Obtains the automatic completion state for this module based on any conditions * in assign settings. * * @param object $course Course * @param object $cm Course-module * @param int $userid User ID * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) * @return bool True if completed, false if not, $type if conditions not set. */ function assign_get_completion_state($course, $cm, $userid, $type) { global $CFG, $DB; require_once $CFG->dirroot . '/mod/assign/locallib.php'; $assign = new assign(null, $cm, $course); // If completion option is enabled, evaluate it and return true/false. if ($assign->get_instance()->completionsubmit) { $submission = $DB->get_record('assign_submission', array('assignment' => $assign->get_instance()->id, 'userid' => $userid), '*', IGNORE_MISSING); return $submission && $submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED; } else { // Completion option is not enabled so just return $type. return $type; } }
/** * Save multiple student grades for a single assignment. * * @param int $assignmentid The id of the assignment * @param boolean $applytoall If set to true and this is a team assignment, * apply the grade to all members of the group * @param array $grades grade data for one or more students that includes * userid - The id of the student being graded * grade - The grade (ignored if the assignment uses advanced grading) * attemptnumber - The attempt number * addattempt - Allow another attempt * workflowstate - New workflow state * plugindata - Custom data used by plugins * advancedgradingdata - Optional Advanced grading data * @throws invalid_parameter_exception if multiple grades are supplied for * a team assignment that has $applytoall set to true * @return null * @since Moodle 2.7 */ public static function save_grades($assignmentid, $applytoall = false, $grades) { global $CFG, $USER; require_once "{$CFG->dirroot}/mod/assign/locallib.php"; $params = self::validate_parameters(self::save_grades_parameters(), array('assignmentid' => $assignmentid, 'applytoall' => $applytoall, 'grades' => $grades)); $cm = get_coursemodule_from_instance('assign', $params['assignmentid'], 0, false, MUST_EXIST); $context = context_module::instance($cm->id); self::validate_context($context); $assignment = new assign($context, $cm, null); if ($assignment->get_instance()->teamsubmission && $params['applytoall']) { // Check that only 1 user per submission group is provided. $groupids = array(); foreach ($params['grades'] as $gradeinfo) { $group = $assignment->get_submission_group($gradeinfo['userid']); if (in_array($group->id, $groupids)) { throw new invalid_parameter_exception('Multiple grades for the same team have been supplied ' . ' this is not permitted when the applytoall flag is set'); } else { $groupids[] = $group->id; } } } foreach ($params['grades'] as $gradeinfo) { $gradedata = (object) $gradeinfo['plugindata']; $gradedata->addattempt = $gradeinfo['addattempt']; $gradedata->attemptnumber = $gradeinfo['attemptnumber']; $gradedata->workflowstate = $gradeinfo['workflowstate']; $gradedata->applytoall = $params['applytoall']; $gradedata->grade = $gradeinfo['grade']; if (!empty($gradeinfo['advancedgradingdata'])) { $advancedgrading = array(); $criteria = reset($gradeinfo['advancedgradingdata']); foreach ($criteria as $key => $criterion) { $details = array(); foreach ($criterion as $value) { foreach ($value['fillings'] as $filling) { $details[$value['criterionid']] = $filling; } } $advancedgrading[$key] = $details; } $gradedata->advancedgrading = $advancedgrading; } $assignment->save_grade($gradeinfo['userid'], $gradedata); } return null; }
// Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Delete the response from the teacher + all comments * * @package assignfeedback_pdf * @copyright 2014 Davo Smith * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once dirname(__FILE__) . '/../../../../config.php'; global $DB, $PAGE, $CFG; require_once $CFG->dirroot . '/mod/assign/locallib.php'; require_once $CFG->dirroot . '/mod/assign/submission/pdf/lib.php'; $id = required_param('id', PARAM_INT); $submissionid = required_param('submissionid', PARAM_INT); $returnparams = required_param('returnparams', PARAM_TEXT); $cm = get_coursemodule_from_id('assign', $id, 0, false, MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); $url = new moodle_url('/mod/assign/feedback/pdf/delete.php', array('id' => $id, 'submissionid' => $submissionid, 'returnparams' => $returnparams)); $PAGE->set_url($url); require_login($course, false, $cm); $context = context_module::instance($cm->id); $assignment = new assign($context, $cm, $course); $feedbackpdf = new assign_feedback_pdf($assignment, 'feedback_pdf'); $submission = $DB->get_record('assign_submission', array('id' => $submissionid, 'assignment' => $assignment->get_instance()->id), '*', MUST_EXIST); $feedbackpdf->delete_feedback($submission);
/** * Obtains the automatic completion state for this module based on any conditions * in assign settings. * * @param object $course Course * @param object $cm Course-module * @param int $userid User ID * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) * @return bool True if completed, false if not, $type if conditions not set. */ function assign_get_completion_state($course, $cm, $userid, $type) { global $CFG, $DB; require_once $CFG->dirroot . '/mod/assign/locallib.php'; $assign = new assign(null, $cm, $course); // If completion option is enabled, evaluate it and return true/false. if ($assign->get_instance()->completionsubmit) { if ($assign->get_instance()->teamsubmission) { $submission = $assign->get_group_submission($userid, 0, false); } else { $submission = $assign->get_user_submission($userid, false); } return $submission && $submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED; } else { // Completion option is not enabled so just return $type. return $type; } }
/** * This function converts all of the base settings for an instance of * the old assignment to the new format. Then it calls each of the plugins * to see if they can help upgrade this assignment. * @param int $oldassignmentid (don't rely on the old assignment type even being installed) * @param string $log This string gets appended to during the conversion process * @return bool true or false */ public function upgrade_assignment($oldassignmentid, &$log) { global $DB, $CFG, $USER; // Steps to upgrade an assignment. // Is the user the admin? admin check goes here. if (!is_siteadmin($USER->id)) { return false; } core_php_time_limit::raise(ASSIGN_MAX_UPGRADE_TIME_SECS); // Get the module details. $oldmodule = $DB->get_record('modules', array('name' => 'assignment'), '*', MUST_EXIST); $params = array('module' => $oldmodule->id, 'instance' => $oldassignmentid); $oldcoursemodule = $DB->get_record('course_modules', $params, '*', MUST_EXIST); $oldcontext = context_module::instance($oldcoursemodule->id); // First insert an assign instance to get the id. $oldassignment = $DB->get_record('assignment', array('id' => $oldassignmentid), '*', MUST_EXIST); $oldversion = get_config('assignment_' . $oldassignment->assignmenttype, 'version'); $data = new stdClass(); $data->course = $oldassignment->course; $data->name = $oldassignment->name; $data->intro = $oldassignment->intro; $data->introformat = $oldassignment->introformat; $data->alwaysshowdescription = 1; $data->sendnotifications = $oldassignment->emailteachers; $data->sendlatenotifications = $oldassignment->emailteachers; $data->duedate = $oldassignment->timedue; $data->allowsubmissionsfromdate = $oldassignment->timeavailable; $data->grade = $oldassignment->grade; $data->submissiondrafts = $oldassignment->resubmit; $data->requiresubmissionstatement = 0; $data->markingworkflow = 0; $data->markingallocation = 0; $data->cutoffdate = 0; // New way to specify no late submissions. if ($oldassignment->preventlate) { $data->cutoffdate = $data->duedate; } $data->teamsubmission = 0; $data->requireallteammemberssubmit = 0; $data->teamsubmissiongroupingid = 0; $data->blindmarking = 0; $data->attemptreopenmethod = 'none'; $data->maxattempts = ASSIGN_UNLIMITED_ATTEMPTS; $newassignment = new assign(null, null, null); if (!$newassignment->add_instance($data, false)) { $log = get_string('couldnotcreatenewassignmentinstance', 'mod_assign'); return false; } // Now create a new coursemodule from the old one. $newmodule = $DB->get_record('modules', array('name' => 'assign'), '*', MUST_EXIST); $newcoursemodule = $this->duplicate_course_module($oldcoursemodule, $newmodule->id, $newassignment->get_instance()->id); if (!$newcoursemodule) { $log = get_string('couldnotcreatenewcoursemodule', 'mod_assign'); return false; } // Convert the base database tables (assignment, submission, grade). // These are used to store information in case a rollback is required. $gradingarea = null; $gradingdefinitions = null; $gradeidmap = array(); $completiondone = false; $gradesdone = false; // From this point we want to rollback on failure. $rollback = false; try { $newassignment->set_context(context_module::instance($newcoursemodule->id)); // The course module has now been created - time to update the core tables. // Copy intro files. $newassignment->copy_area_files_for_upgrade($oldcontext->id, 'mod_assignment', 'intro', 0, $newassignment->get_context()->id, 'mod_assign', 'intro', 0); // Get the plugins to do their bit. foreach ($newassignment->get_submission_plugins() as $plugin) { if ($plugin->can_upgrade($oldassignment->assignmenttype, $oldversion)) { $plugin->enable(); if (!$plugin->upgrade_settings($oldcontext, $oldassignment, $log)) { $rollback = true; } } else { $plugin->disable(); } } foreach ($newassignment->get_feedback_plugins() as $plugin) { if ($plugin->can_upgrade($oldassignment->assignmenttype, $oldversion)) { $plugin->enable(); if (!$plugin->upgrade_settings($oldcontext, $oldassignment, $log)) { $rollback = true; } } else { $plugin->disable(); } } // See if there is advanced grading upgrades required. $gradingarea = $DB->get_record('grading_areas', array('contextid' => $oldcontext->id, 'areaname' => 'submission'), '*', IGNORE_MISSING); if ($gradingarea) { $params = array('id' => $gradingarea->id, 'contextid' => $newassignment->get_context()->id, 'component' => 'mod_assign', 'areaname' => 'submissions'); $DB->update_record('grading_areas', $params); $gradingdefinitions = $DB->get_records('grading_definitions', array('areaid' => $gradingarea->id)); } // Upgrade availability data. \core_availability\info::update_dependency_id_across_course($newcoursemodule->course, 'course_modules', $oldcoursemodule->id, $newcoursemodule->id); // Upgrade completion data. $DB->set_field('course_modules_completion', 'coursemoduleid', $newcoursemodule->id, array('coursemoduleid' => $oldcoursemodule->id)); $allcriteria = $DB->get_records('course_completion_criteria', array('moduleinstance' => $oldcoursemodule->id)); foreach ($allcriteria as $criteria) { $criteria->module = 'assign'; $criteria->moduleinstance = $newcoursemodule->id; $DB->update_record('course_completion_criteria', $criteria); } $completiondone = true; // Migrate log entries so we don't lose them. $logparams = array('cmid' => $oldcoursemodule->id, 'course' => $oldcoursemodule->course); $DB->set_field('log', 'module', 'assign', $logparams); $DB->set_field('log', 'cmid', $newcoursemodule->id, $logparams); // Copy all the submission data (and get plugins to do their bit). $oldsubmissions = $DB->get_records('assignment_submissions', array('assignment' => $oldassignmentid)); foreach ($oldsubmissions as $oldsubmission) { $submission = new stdClass(); $submission->assignment = $newassignment->get_instance()->id; $submission->userid = $oldsubmission->userid; $submission->timecreated = $oldsubmission->timecreated; $submission->timemodified = $oldsubmission->timemodified; $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED; $submission->id = $DB->insert_record('assign_submission', $submission); if (!$submission->id) { $log .= get_string('couldnotinsertsubmission', 'mod_assign', $submission->userid); $rollback = true; } foreach ($newassignment->get_submission_plugins() as $plugin) { if ($plugin->can_upgrade($oldassignment->assignmenttype, $oldversion)) { if (!$plugin->upgrade($oldcontext, $oldassignment, $oldsubmission, $submission, $log)) { $rollback = true; } } } if ($oldsubmission->timemarked) { // Submission has been graded - create a grade record. $grade = new stdClass(); $grade->assignment = $newassignment->get_instance()->id; $grade->userid = $oldsubmission->userid; $grade->grader = $oldsubmission->teacher; $grade->timemodified = $oldsubmission->timemarked; $grade->timecreated = $oldsubmission->timecreated; $grade->grade = $oldsubmission->grade; if ($oldsubmission->mailed) { // The mailed flag goes in the flags table. $flags = new stdClass(); $flags->userid = $oldsubmission->userid; $flags->assignment = $newassignment->get_instance()->id; $flags->mailed = 1; $DB->insert_record('assign_user_flags', $flags); } $grade->id = $DB->insert_record('assign_grades', $grade); if (!$grade->id) { $log .= get_string('couldnotinsertgrade', 'mod_assign', $grade->userid); $rollback = true; } // Copy any grading instances. if ($gradingarea) { $gradeidmap[$grade->id] = $oldsubmission->id; foreach ($gradingdefinitions as $definition) { $params = array('definitionid' => $definition->id, 'itemid' => $oldsubmission->id); $DB->set_field('grading_instances', 'itemid', $grade->id, $params); } } foreach ($newassignment->get_feedback_plugins() as $plugin) { if ($plugin->can_upgrade($oldassignment->assignmenttype, $oldversion)) { if (!$plugin->upgrade($oldcontext, $oldassignment, $oldsubmission, $grade, $log)) { $rollback = true; } } } } } $newassignment->update_calendar($newcoursemodule->id); // Reassociate grade_items from the old assignment instance to the new assign instance. // This includes outcome linked grade_items. $params = array('assign', $newassignment->get_instance()->id, 'assignment', $oldassignment->id); $sql = 'UPDATE {grade_items} SET itemmodule = ?, iteminstance = ? WHERE itemmodule = ? AND iteminstance = ?'; $DB->execute($sql, $params); // Create a mapping record to map urls from the old to the new assignment. $mapping = new stdClass(); $mapping->oldcmid = $oldcoursemodule->id; $mapping->oldinstance = $oldassignment->id; $mapping->newcmid = $newcoursemodule->id; $mapping->newinstance = $newassignment->get_instance()->id; $mapping->timecreated = time(); $DB->insert_record('assignment_upgrade', $mapping); $gradesdone = true; } catch (Exception $exception) { $rollback = true; $log .= get_string('conversionexception', 'mod_assign', $exception->getMessage()); } if ($rollback) { // Roll back the grades changes. if ($gradesdone) { // Reassociate grade_items from the new assign instance to the old assignment instance. $params = array('assignment', $oldassignment->id, 'assign', $newassignment->get_instance()->id); $sql = 'UPDATE {grade_items} SET itemmodule = ?, iteminstance = ? WHERE itemmodule = ? AND iteminstance = ?'; $DB->execute($sql, $params); } // Roll back the completion changes. if ($completiondone) { $DB->set_field('course_modules_completion', 'coursemoduleid', $oldcoursemodule->id, array('coursemoduleid' => $newcoursemodule->id)); $allcriteria = $DB->get_records('course_completion_criteria', array('moduleinstance' => $newcoursemodule->id)); foreach ($allcriteria as $criteria) { $criteria->module = 'assignment'; $criteria->moduleinstance = $oldcoursemodule->id; $DB->update_record('course_completion_criteria', $criteria); } } // Roll back the log changes. $logparams = array('cmid' => $newcoursemodule->id, 'course' => $newcoursemodule->course); $DB->set_field('log', 'module', 'assignment', $logparams); $DB->set_field('log', 'cmid', $oldcoursemodule->id, $logparams); // Roll back the advanced grading update. if ($gradingarea) { foreach ($gradeidmap as $newgradeid => $oldsubmissionid) { foreach ($gradingdefinitions as $definition) { $DB->set_field('grading_instances', 'itemid', $oldsubmissionid, array('definitionid' => $definition->id, 'itemid' => $newgradeid)); } } $params = array('id' => $gradingarea->id, 'contextid' => $oldcontext->id, 'component' => 'mod_assignment', 'areaname' => 'submission'); $DB->update_record('grading_areas', $params); } $newassignment->delete_instance(); return false; } // Delete the old assignment (use object delete). $cm = get_coursemodule_from_id('', $oldcoursemodule->id, $oldcoursemodule->course); if ($cm) { course_delete_module($cm->id); } rebuild_course_cache($oldcoursemodule->course); return true; }
/** * Returns submissions for the requested assignment ids * * @param int[] $assignmentids * @param string $status only return submissions with this status * @param int $since only return submissions with timemodified >= since * @param int $before only return submissions with timemodified <= before * @return array of submissions for each requested assignment * @since Moodle 2.5 */ public static function get_submissions($assignmentids, $status = '', $since = 0, $before = 0) { global $DB, $CFG; $params = self::validate_parameters(self::get_submissions_parameters(), array('assignmentids' => $assignmentids, 'status' => $status, 'since' => $since, 'before' => $before)); $warnings = array(); $assignments = array(); // Check the user is allowed to get the submissions for the assignments requested. $placeholders = array(); list($inorequalsql, $placeholders) = $DB->get_in_or_equal($params['assignmentids'], SQL_PARAMS_NAMED); $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module " . "WHERE md.name = :modname AND cm.instance " . $inorequalsql; $placeholders['modname'] = 'assign'; $cms = $DB->get_records_sql($sql, $placeholders); $assigns = array(); foreach ($cms as $cm) { try { $context = context_module::instance($cm->id); self::validate_context($context); require_capability('mod/assign:grade', $context); $assign = new assign($context, null, null); $assigns[] = $assign; } catch (Exception $e) { $warnings[] = array('item' => 'assignment', 'itemid' => $cm->instance, 'warningcode' => '1', 'message' => 'No access rights in module context'); } } foreach ($assigns as $assign) { $submissions = array(); $placeholders = array('assignid1' => $assign->get_instance()->id, 'assignid2' => $assign->get_instance()->id); $submissionmaxattempt = 'SELECT mxs.userid, MAX(mxs.attemptnumber) AS maxattempt FROM {assign_submission} mxs WHERE mxs.assignment = :assignid1 GROUP BY mxs.userid'; $sql = "SELECT mas.id, mas.assignment,mas.userid," . "mas.timecreated,mas.timemodified,mas.status,mas.groupid,mas.attemptnumber " . "FROM {assign_submission} mas " . "JOIN ( " . $submissionmaxattempt . " ) smx ON mas.userid = smx.userid " . "WHERE mas.assignment = :assignid2 AND mas.attemptnumber = smx.maxattempt"; if (!empty($params['status'])) { $placeholders['status'] = $params['status']; $sql = $sql . " AND mas.status = :status"; } if (!empty($params['before'])) { $placeholders['since'] = $params['since']; $placeholders['before'] = $params['before']; $sql = $sql . " AND mas.timemodified BETWEEN :since AND :before"; } else { $placeholders['since'] = $params['since']; $sql = $sql . " AND mas.timemodified >= :since"; } $submissionrecords = $DB->get_records_sql($sql, $placeholders); if (!empty($submissionrecords)) { $submissionplugins = $assign->get_submission_plugins(); foreach ($submissionrecords as $submissionrecord) { $submission = array('id' => $submissionrecord->id, 'userid' => $submissionrecord->userid, 'timecreated' => $submissionrecord->timecreated, 'timemodified' => $submissionrecord->timemodified, 'status' => $submissionrecord->status, 'attemptnumber' => $submissionrecord->attemptnumber, 'groupid' => $submissionrecord->groupid, 'plugins' => self::get_plugins_data($assign, $submissionplugins, $submissionrecord)); $submissions[] = $submission; } } else { $warnings[] = array('item' => 'module', 'itemid' => $assign->get_instance()->id, 'warningcode' => '3', 'message' => 'No submissions found'); } $assignments[] = array('assignmentid' => $assign->get_instance()->id, 'submissions' => $submissions); } $result = array('assignments' => $assignments, 'warnings' => $warnings); return $result; }
/** * Returns submissions for the requested assignment ids * * @param array of ints $assignmentids * @param string $status only return submissions with this status * @param int $since only return submissions with timemodified >= since * @param int $before only return submissions with timemodified <= before * @return array of submissions for each requested assignment * @since Moodle 2.5 */ public static function get_submissions($assignmentids, $status = '', $since = 0, $before = 0) { global $DB, $CFG; require_once("$CFG->dirroot/mod/assign/locallib.php"); $params = self::validate_parameters(self::get_submissions_parameters(), array('assignmentids' => $assignmentids, 'status' => $status, 'since' => $since, 'before' => $before)); $warnings = array(); $assignments = array(); // Check the user is allowed to get the submissions for the assignments requested. $placeholders = array(); list($inorequalsql, $placeholders) = $DB->get_in_or_equal($params['assignmentids'], SQL_PARAMS_NAMED); $sql = "SELECT cm.id, cm.instance FROM {course_modules} cm JOIN {modules} md ON md.id = cm.module ". "WHERE md.name = :modname AND cm.instance ".$inorequalsql; $placeholders['modname'] = 'assign'; $cms = $DB->get_records_sql($sql, $placeholders); $assigns = array(); foreach ($cms as $cm) { try { $context = context_module::instance($cm->id); self::validate_context($context); require_capability('mod/assign:grade', $context); $assign = new assign($context, null, null); $assigns[] = $assign; } catch (Exception $e) { $warnings[] = array( 'item' => 'assignment', 'itemid' => $cm->instance, 'warningcode' => '1', 'message' => 'No access rights in module context' ); } } foreach ($assigns as $assign) { $submissions = array(); $submissionplugins = $assign->get_submission_plugins(); $placeholders = array('assignid1' => $assign->get_instance()->id, 'assignid2' => $assign->get_instance()->id); $submissionmaxattempt = 'SELECT mxs.userid, MAX(mxs.attemptnumber) AS maxattempt FROM {assign_submission} mxs WHERE mxs.assignment = :assignid1 GROUP BY mxs.userid'; $sql = "SELECT mas.id, mas.assignment,mas.userid,". "mas.timecreated,mas.timemodified,mas.status,mas.groupid ". "FROM {assign_submission} mas ". "JOIN ( " . $submissionmaxattempt . " ) smx ON mas.userid = smx.userid ". "WHERE mas.assignment = :assignid2 AND mas.attemptnumber = smx.maxattempt"; if (!empty($params['status'])) { $placeholders['status'] = $params['status']; $sql = $sql." AND mas.status = :status"; } if (!empty($params['before'])) { $placeholders['since'] = $params['since']; $placeholders['before'] = $params['before']; $sql = $sql." AND mas.timemodified BETWEEN :since AND :before"; } else { $placeholders['since'] = $params['since']; $sql = $sql." AND mas.timemodified >= :since"; } $submissionrecords = $DB->get_records_sql($sql, $placeholders); if (!empty($submissionrecords)) { $fs = get_file_storage(); foreach ($submissionrecords as $submissionrecord) { $submission = array( 'id' => $submissionrecord->id, 'userid' => $submissionrecord->userid, 'timecreated' => $submissionrecord->timecreated, 'timemodified' => $submissionrecord->timemodified, 'status' => $submissionrecord->status, 'groupid' => $submissionrecord->groupid ); foreach ($submissionplugins as $submissionplugin) { $plugin = array( 'name' => $submissionplugin->get_name(), 'type' => $submissionplugin->get_type() ); // Subtype is 'assignsubmission', type is currently 'file' or 'onlinetext'. $component = $submissionplugin->get_subtype().'_'.$submissionplugin->get_type(); $fileareas = $submissionplugin->get_file_areas(); foreach ($fileareas as $filearea => $name) { $fileareainfo = array('area' => $filearea); $files = $fs->get_area_files( $assign->get_context()->id, $component, $filearea, $submissionrecord->id, "timemodified", false ); foreach ($files as $file) { $filepath = array('filepath' => $file->get_filepath().$file->get_filename()); $fileareainfo['files'][] = $filepath; } $plugin['fileareas'][] = $fileareainfo; } $editorfields = $submissionplugin->get_editor_fields(); foreach ($editorfields as $name => $description) { $editorfieldinfo = array( 'name' => $name, 'description' => $description, 'text' => $submissionplugin->get_editor_text($name, $submissionrecord->id), 'format' => $submissionplugin->get_editor_format($name, $submissionrecord->id) ); $plugin['editorfields'][] = $editorfieldinfo; } $submission['plugins'][] = $plugin; } $submissions[] = $submission; } } else { $warnings[] = array( 'item' => 'module', 'itemid' => $assign->get_instance()->id, 'warningcode' => '3', 'message' => 'No submissions found' ); } $assignments[] = array( 'assignmentid' => $assign->get_instance()->id, 'submissions' => $submissions ); } $result = array( 'assignments' => $assignments, 'warnings' => $warnings ); return $result; }
/** * Return things to the renderer. * * @return string the assignment name */ public function get_assignment_name() { return $this->assignment->get_instance()->name; }
/** * Makes the grading interface for the pop up. Robbed from /mod/assign/locallib.php * line 1583ish - view_single_grade_page(). * * @param array $params From $_GET * @param object $coursemodule The coursemodule object that the user has been authenticated * against * @param bool $data * @throws coding_exception * @global $PAGE * @global stdClass $CFG * @global moodle_database $DB * @global $OUTPUT * @global stdClass $USER * @return string */ public function grading_popup($params, $coursemodule, $data = false) { global $PAGE, $CFG, $DB; $modulecontext = context_module::instance($coursemodule->id); $course = $DB->get_record('course', array('id' => $coursemodule->course)); $coursecontext = context_course::instance($course->id); $assign = new assign($modulecontext, $coursemodule, $course); /* @var mod_assign_renderer $renderer */ $renderer = $PAGE->get_renderer('mod_assign'); $output = ''; // Include grade form. require_once $CFG->dirroot . '/mod/assign/gradeform.php'; // Need submit permission to submit an assignment. require_capability('mod/assign:grade', $modulecontext); /* Pinched from private method assign::get_grading_userid_list() */ $filter = get_user_preferences('assign_filter', ''); $table = new assign_grading_table($assign, 0, $filter, 0, false); $useridlist = $table->get_column_data('userid'); $userid = $params['userid']; $rownum = 0; foreach ($useridlist as $key => $useridinlist) { if ($useridinlist == $userid) { $rownum = $key; reset($useridlist); // Just in case. break; } } $last = false; if ($rownum == count($useridlist) - 1) { $last = true; } $user = $DB->get_record('user', array('id' => $userid)); if ($user) { $output .= $renderer->render(new assign_user_summary($user, $course->id, has_capability('moodle/site:viewfullnames', $coursecontext))); } $submission = $DB->get_record('assign_submission', array('assignment' => $assign->get_instance()->id, 'userid' => $userid)); // Get the current grade. Pinched from assign::get_user_grade(). $grade = $DB->get_record('assign_grades', array('assignment' => $assign->get_instance()->id, 'userid' => $userid)); // Pinched from assign::is_graded(). $isgraded = !empty($grade) && $grade->grade !== null && $grade->grade >= 0; if ($assign->can_view_submission($userid)) { $gradelocked = $grade && $grade->locked || $assign->grading_disabled($userid); $widget = new assign_submission_status($assign->get_instance()->allowsubmissionsfromdate, $assign->get_instance()->alwaysshowdescription, $submission, $assign->is_any_submission_plugin_enabled(), $gradelocked, $isgraded, $assign->get_instance()->duedate, $assign->get_submission_plugins(), $assign->get_return_action(), $assign->get_return_params(), $assign->get_course_module()->id, assign_submission_status::GRADER_VIEW, false, false); $output .= $renderer->render($widget); } if ($grade) { $data = new stdClass(); if ($grade->grade !== null && $grade->grade >= 0) { $data->grade = format_float($grade->grade, 2); } } else { $data = new stdClass(); $data->grade = ''; } // Now show the grading form. $customdata = array('useridlist' => $useridlist, 'rownum' => $rownum, 'last' => $last); $mform = new mod_assign_grade_form(block_ajax_marking_form_url($params), array($assign, $data, $customdata), 'post', '', array('class' => 'gradeform')); $output .= $renderer->render(new assign_form('gradingform', $mform)); $assign->add_to_log('view grading form', get_string('viewgradingformforstudent', 'assign', array('id' => $user->id, 'fullname' => fullname($user)))); return $output; }