/mod/assign/locallib.php
PHP | 3377 lines | 2037 code | 481 blank | 859 comment | 430 complexity | 52364399fde9e76d730c2878f3c9b36e MD5 | raw file
Possible License(s): AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, Apache-2.0, GPL-3.0, BSD-3-Clause, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- <?php
- // This file is part of Moodle - http://moodle.org/
- //
- // Moodle is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // 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/>.
- /**
- * This file contains the definition for the class assignment
- *
- * This class provides all the functionality for the new assign module.
- *
- * @package mod_assign
- * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- defined('MOODLE_INTERNAL') || die();
- /**
- * Assignment submission statuses
- */
- define('ASSIGN_SUBMISSION_STATUS_DRAFT', 'draft'); // student thinks it is a draft
- define('ASSIGN_SUBMISSION_STATUS_SUBMITTED', 'submitted'); // student thinks it is finished
- /**
- * Search filters for grading page
- */
- define('ASSIGN_FILTER_SUBMITTED', 'submitted');
- define('ASSIGN_FILTER_SINGLE_USER', 'singleuser');
- define('ASSIGN_FILTER_REQUIRE_GRADING', 'require_grading');
- /** Include accesslib.php */
- require_once($CFG->libdir.'/accesslib.php');
- /** Include formslib.php */
- require_once($CFG->libdir.'/formslib.php');
- /** Include repository/lib.php */
- require_once($CFG->dirroot . '/repository/lib.php');
- /** Include local mod_form.php */
- require_once($CFG->dirroot.'/mod/assign/mod_form.php');
- /** gradelib.php */
- require_once($CFG->libdir.'/gradelib.php');
- /** grading lib.php */
- require_once($CFG->dirroot.'/grade/grading/lib.php');
- /** Include feedbackplugin.php */
- require_once($CFG->dirroot.'/mod/assign/feedbackplugin.php');
- /** Include submissionplugin.php */
- require_once($CFG->dirroot.'/mod/assign/submissionplugin.php');
- /** Include renderable.php */
- require_once($CFG->dirroot.'/mod/assign/renderable.php');
- /** Include gradingtable.php */
- require_once($CFG->dirroot.'/mod/assign/gradingtable.php');
- /** Include eventslib.php */
- require_once($CFG->libdir.'/eventslib.php');
- /**
- * Standard base class for mod_assign (assignment types).
- *
- * @package mod_assign
- * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- class assign {
- /** @var stdClass the assignment record that contains the global settings for this assign instance */
- private $instance;
- /** @var context the context of the course module for this assign instance (or just the course if we are
- creating a new one) */
- private $context;
- /** @var stdClass the course this assign instance belongs to */
- private $course;
- /** @var stdClass the admin config for all assign instances */
- private $adminconfig;
- /** @var assign_renderer the custom renderer for this module */
- private $output;
- /** @var stdClass the course module for this assign instance */
- private $coursemodule;
- /** @var array cache for things like the coursemodule name or the scale menu - only lives for a single
- request */
- private $cache;
- /** @var array list of the installed submission plugins */
- private $submissionplugins;
- /** @var array list of the installed feedback plugins */
- private $feedbackplugins;
- /** @var string action to be used to return to this page (without repeating any form submissions etc.) */
- private $returnaction = 'view';
- /** @var array params to be used to return to this page */
- private $returnparams = array();
- /** @var string modulename prevents excessive calls to get_string */
- private static $modulename = null;
- /** @var string modulenameplural prevents excessive calls to get_string */
- private static $modulenameplural = null;
- /**
- * Constructor for the base assign class
- *
- * @param mixed $coursemodulecontext context|null the course module context (or the course context if the coursemodule has not been created yet)
- * @param mixed $coursemodule the current course module if it was already loaded - otherwise this class will load one from the context as required
- * @param mixed $course the current course if it was already loaded - otherwise this class will load one from the context as required
- */
- public function __construct($coursemodulecontext, $coursemodule, $course) {
- global $PAGE;
- $this->context = $coursemodulecontext;
- $this->coursemodule = $coursemodule;
- $this->course = $course;
- $this->cache = array(); // temporary cache only lives for a single request - used to reduce db lookups
- $this->submissionplugins = $this->load_plugins('assignsubmission');
- $this->feedbackplugins = $this->load_plugins('assignfeedback');
- $this->output = $PAGE->get_renderer('mod_assign');
- }
- /**
- * Set the action and parameters that can be used to return to the current page
- *
- * @param string $action The action for the current page
- * @param array $params An array of name value pairs which form the parameters to return to the current page
- * @return void
- */
- public function register_return_link($action, $params) {
- $this->returnaction = $action;
- $this->returnparams = $params;
- }
- /**
- * Return an action that can be used to get back to the current page
- * @return string action
- */
- public function get_return_action() {
- return $this->returnaction;
- }
- /**
- * Based on the current assignment settings should we display the intro
- * @return bool showintro
- */
- private function show_intro() {
- if ($this->get_instance()->alwaysshowdescription ||
- time() > $this->get_instance()->allowsubmissionsfromdate) {
- return true;
- }
- return false;
- }
- /**
- * Return a list of parameters that can be used to get back to the current page
- * @return array params
- */
- public function get_return_params() {
- return $this->returnparams;
- }
- /**
- * Set the submitted form data
- * @param stdClass $data The form data (instance)
- */
- public function set_instance(stdClass $data) {
- $this->instance = $data;
- }
- /**
- * Set the context
- * @param context $context The new context
- */
- public function set_context(context $context) {
- $this->context = $context;
- }
- /**
- * Set the course data
- * @param stdClass $course The course data
- */
- public function set_course(stdClass $course) {
- $this->course = $course;
- }
- /**
- * get list of feedback plugins installed
- * @return array
- */
- public function get_feedback_plugins() {
- return $this->feedbackplugins;
- }
- /**
- * get list of submission plugins installed
- * @return array
- */
- public function get_submission_plugins() {
- return $this->submissionplugins;
- }
- /**
- * get a specific submission plugin by its type
- * @param string $subtype assignsubmission | assignfeedback
- * @param string $type
- * @return mixed assign_plugin|null
- */
- private function get_plugin_by_type($subtype, $type) {
- $shortsubtype = substr($subtype, strlen('assign'));
- $name = $shortsubtype . 'plugins';
- $pluginlist = $this->$name;
- foreach ($pluginlist as $plugin) {
- if ($plugin->get_type() == $type) {
- return $plugin;
- }
- }
- return null;
- }
- /**
- * Get a feedback plugin by type
- * @param string $type - The type of plugin e.g comments
- * @return mixed assign_feedback_plugin|null
- */
- public function get_feedback_plugin_by_type($type) {
- return $this->get_plugin_by_type('assignfeedback', $type);
- }
- /**
- * Get a submission plugin by type
- * @param string $type - The type of plugin e.g comments
- * @return mixed assign_submission_plugin|null
- */
- public function get_submission_plugin_by_type($type) {
- return $this->get_plugin_by_type('assignsubmission', $type);
- }
- /**
- * Load the plugins from the sub folders under subtype
- * @param string $subtype - either submission or feedback
- * @return array - The sorted list of plugins
- */
- private function load_plugins($subtype) {
- global $CFG;
- $result = array();
- $names = get_plugin_list($subtype);
- foreach ($names as $name => $path) {
- if (file_exists($path . '/locallib.php')) {
- require_once($path . '/locallib.php');
- $shortsubtype = substr($subtype, strlen('assign'));
- $pluginclass = 'assign_' . $shortsubtype . '_' . $name;
- $plugin = new $pluginclass($this, $name);
- if ($plugin instanceof assign_plugin) {
- $idx = $plugin->get_sort_order();
- while (array_key_exists($idx, $result)) $idx +=1;
- $result[$idx] = $plugin;
- }
- }
- }
- ksort($result);
- return $result;
- }
- /**
- * Display the assignment, used by view.php
- *
- * The assignment is displayed differently depending on your role,
- * the settings for the assignment and the status of the assignment.
- * @param string $action The current action if any.
- * @return void
- */
- public function view($action='') {
- $o = '';
- $mform = null;
- // handle form submissions first
- if ($action == 'savesubmission') {
- $action = 'editsubmission';
- if ($this->process_save_submission($mform)) {
- $action = 'view';
- }
- } else if ($action == 'lock') {
- $this->process_lock();
- $action = 'grading';
- } else if ($action == 'reverttodraft') {
- $this->process_revert_to_draft();
- $action = 'grading';
- } else if ($action == 'unlock') {
- $this->process_unlock();
- $action = 'grading';
- } else if ($action == 'confirmsubmit') {
- $this->process_submit_for_grading();
- // save and show next button
- } else if ($action == 'batchgradingoperation') {
- $this->process_batch_grading_operation();
- $action = 'grading';
- } else if ($action == 'submitgrade') {
- if (optional_param('saveandshownext', null, PARAM_ALPHA)) {
- //save and show next
- $action = 'grade';
- if ($this->process_save_grade($mform)) {
- $action = 'nextgrade';
- }
- } else if (optional_param('nosaveandprevious', null, PARAM_ALPHA)) {
- $action = 'previousgrade';
- } else if (optional_param('nosaveandnext', null, PARAM_ALPHA)) {
- //show next button
- $action = 'nextgrade';
- } else if (optional_param('savegrade', null, PARAM_ALPHA)) {
- //save changes button
- $action = 'grade';
- if ($this->process_save_grade($mform)) {
- $action = 'grading';
- }
- } else {
- //cancel button
- $action = 'grading';
- }
- }else if ($action == 'quickgrade') {
- $message = $this->process_save_quick_grades();
- $action = 'quickgradingresult';
- }else if ($action == 'saveoptions') {
- $this->process_save_grading_options();
- $action = 'grading';
- }
- $returnparams = array('rownum'=>optional_param('rownum', 0, PARAM_INT));
- $this->register_return_link($action, $returnparams);
- // now show the right view page
- if ($action == 'previousgrade') {
- $mform = null;
- $o .= $this->view_single_grade_page($mform, -1);
- } else if ($action == 'quickgradingresult') {
- $mform = null;
- $o .= $this->view_quickgrading_result($message);
- } else if ($action == 'nextgrade') {
- $mform = null;
- $o .= $this->view_single_grade_page($mform, 1);
- } else if ($action == 'grade') {
- $o .= $this->view_single_grade_page($mform);
- } else if ($action == 'viewpluginassignfeedback') {
- $o .= $this->view_plugin_content('assignfeedback');
- } else if ($action == 'viewpluginassignsubmission') {
- $o .= $this->view_plugin_content('assignsubmission');
- } else if ($action == 'editsubmission') {
- $o .= $this->view_edit_submission_page($mform);
- } else if ($action == 'grading') {
- $o .= $this->view_grading_page();
- } else if ($action == 'downloadall') {
- $o .= $this->download_submissions();
- } else if ($action == 'submit') {
- $o .= $this->check_submit_for_grading();
- } else {
- $o .= $this->view_submission_page();
- }
- return $o;
- }
- /**
- * Add this instance to the database
- *
- * @param stdClass $formdata The data submitted from the form
- * @param bool $callplugins This is used to skip the plugin code
- * when upgrading an old assignment to a new one (the plugins get called manually)
- * @return mixed false if an error occurs or the int id of the new instance
- */
- public function add_instance(stdClass $formdata, $callplugins) {
- global $DB;
- $err = '';
- // add the database record
- $update = new stdClass();
- $update->name = $formdata->name;
- $update->timemodified = time();
- $update->timecreated = time();
- $update->course = $formdata->course;
- $update->courseid = $formdata->course;
- $update->intro = $formdata->intro;
- $update->introformat = $formdata->introformat;
- $update->alwaysshowdescription = $formdata->alwaysshowdescription;
- $update->preventlatesubmissions = $formdata->preventlatesubmissions;
- $update->submissiondrafts = $formdata->submissiondrafts;
- $update->sendnotifications = $formdata->sendnotifications;
- $update->sendlatenotifications = $formdata->sendlatenotifications;
- $update->duedate = $formdata->duedate;
- $update->allowsubmissionsfromdate = $formdata->allowsubmissionsfromdate;
- $update->grade = $formdata->grade;
- $returnid = $DB->insert_record('assign', $update);
- $this->instance = $DB->get_record('assign', array('id'=>$returnid), '*', MUST_EXIST);
- // cache the course record
- $this->course = $DB->get_record('course', array('id'=>$formdata->course), '*', MUST_EXIST);
- if ($callplugins) {
- // call save_settings hook for submission plugins
- foreach ($this->submissionplugins as $plugin) {
- if (!$this->update_plugin_instance($plugin, $formdata)) {
- print_error($plugin->get_error());
- return false;
- }
- }
- foreach ($this->feedbackplugins as $plugin) {
- if (!$this->update_plugin_instance($plugin, $formdata)) {
- print_error($plugin->get_error());
- return false;
- }
- }
- // in the case of upgrades the coursemodule has not been set so we need to wait before calling these two
- // TODO: add event to the calendar
- $this->update_calendar($formdata->coursemodule);
- // TODO: add the item in the gradebook
- $this->update_gradebook(false, $formdata->coursemodule);
- }
- $update = new stdClass();
- $update->id = $this->get_instance()->id;
- $update->nosubmissions = (!$this->is_any_submission_plugin_enabled()) ? 1: 0;
- $DB->update_record('assign', $update);
- return $returnid;
- }
- /**
- * Delete all grades from the gradebook for this assignment
- *
- * @return bool
- */
- private function delete_grades() {
- global $CFG;
- return grade_update('mod/assign', $this->get_course()->id, 'mod', 'assign', $this->get_instance()->id, 0, NULL, array('deleted'=>1)) == GRADE_UPDATE_OK;
- }
- /**
- * Delete this instance from the database
- *
- * @return bool false if an error occurs
- */
- public function delete_instance() {
- global $DB;
- $result = true;
- foreach ($this->submissionplugins as $plugin) {
- if (!$plugin->delete_instance()) {
- print_error($plugin->get_error());
- $result = false;
- }
- }
- foreach ($this->feedbackplugins as $plugin) {
- if (!$plugin->delete_instance()) {
- print_error($plugin->get_error());
- $result = false;
- }
- }
- // delete files associated with this assignment
- $fs = get_file_storage();
- if (! $fs->delete_area_files($this->context->id) ) {
- $result = false;
- }
- // delete_records will throw an exception if it fails - so no need for error checking here
- $DB->delete_records('assign_submission', array('assignment'=>$this->get_instance()->id));
- $DB->delete_records('assign_grades', array('assignment'=>$this->get_instance()->id));
- $DB->delete_records('assign_plugin_config', array('assignment'=>$this->get_instance()->id));
- // delete items from the gradebook
- if (! $this->delete_grades()) {
- $result = false;
- }
- // delete the instance
- $DB->delete_records('assign', array('id'=>$this->get_instance()->id));
- return $result;
- }
- /**
- * Update the settings for a single plugin
- *
- * @param assign_plugin $plugin The plugin to update
- * @param stdClass $formdata The form data
- * @return bool false if an error occurs
- */
- private function update_plugin_instance(assign_plugin $plugin, stdClass $formdata) {
- if ($plugin->is_visible()) {
- $enabledname = $plugin->get_subtype() . '_' . $plugin->get_type() . '_enabled';
- if ($formdata->$enabledname) {
- $plugin->enable();
- if (!$plugin->save_settings($formdata)) {
- print_error($plugin->get_error());
- return false;
- }
- } else {
- $plugin->disable();
- }
- }
- return true;
- }
- /**
- * Update the gradebook information for this assignment
- *
- * @param bool $reset If true, will reset all grades in the gradbook for this assignment
- * @param int $coursemoduleid This is required because it might not exist in the database yet
- * @return bool
- */
- public function update_gradebook($reset, $coursemoduleid) {
- global $CFG;
- /** Include lib.php */
- require_once($CFG->dirroot.'/mod/assign/lib.php');
- $assign = clone $this->get_instance();
- $assign->cmidnumber = $coursemoduleid;
- $param = null;
- if ($reset) {
- $param = 'reset';
- }
- return assign_grade_item_update($assign, $param);
- }
- /** Load and cache the admin config for this module
- *
- * @return stdClass the plugin config
- */
- public function get_admin_config() {
- if ($this->adminconfig) {
- return $this->adminconfig;
- }
- $this->adminconfig = get_config('assign');
- return $this->adminconfig;
- }
- /**
- * Update the calendar entries for this assignment
- *
- * @param int $coursemoduleid - Required to pass this in because it might not exist in the database yet
- * @return bool
- */
- public function update_calendar($coursemoduleid) {
- global $DB, $CFG;
- require_once($CFG->dirroot.'/calendar/lib.php');
- // special case for add_instance as the coursemodule has not been set yet.
- if ($this->get_instance()->duedate) {
- $event = new stdClass();
- if ($event->id = $DB->get_field('event', 'id', array('modulename'=>'assign', 'instance'=>$this->get_instance()->id))) {
- $event->name = $this->get_instance()->name;
- $event->description = format_module_intro('assign', $this->get_instance(), $coursemoduleid);
- $event->timestart = $this->get_instance()->duedate;
- $calendarevent = calendar_event::load($event->id);
- $calendarevent->update($event);
- } else {
- $event = new stdClass();
- $event->name = $this->get_instance()->name;
- $event->description = format_module_intro('assign', $this->get_instance(), $coursemoduleid);
- $event->courseid = $this->get_instance()->course;
- $event->groupid = 0;
- $event->userid = 0;
- $event->modulename = 'assign';
- $event->instance = $this->get_instance()->id;
- $event->eventtype = 'due';
- $event->timestart = $this->get_instance()->duedate;
- $event->timeduration = 0;
- calendar_event::create($event);
- }
- } else {
- $DB->delete_records('event', array('modulename'=>'assign', 'instance'=>$this->get_instance()->id));
- }
- }
- /**
- * Update this instance in the database
- *
- * @param stdClass $formdata - the data submitted from the form
- * @return bool false if an error occurs
- */
- public function update_instance($formdata) {
- global $DB;
- $update = new stdClass();
- $update->id = $formdata->instance;
- $update->name = $formdata->name;
- $update->timemodified = time();
- $update->course = $formdata->course;
- $update->intro = $formdata->intro;
- $update->introformat = $formdata->introformat;
- $update->alwaysshowdescription = $formdata->alwaysshowdescription;
- $update->preventlatesubmissions = $formdata->preventlatesubmissions;
- $update->submissiondrafts = $formdata->submissiondrafts;
- $update->sendnotifications = $formdata->sendnotifications;
- $update->sendlatenotifications = $formdata->sendlatenotifications;
- $update->duedate = $formdata->duedate;
- $update->allowsubmissionsfromdate = $formdata->allowsubmissionsfromdate;
- $update->grade = $formdata->grade;
- $result = $DB->update_record('assign', $update);
- $this->instance = $DB->get_record('assign', array('id'=>$update->id), '*', MUST_EXIST);
- // load the assignment so the plugins have access to it
- // call save_settings hook for submission plugins
- foreach ($this->submissionplugins as $plugin) {
- if (!$this->update_plugin_instance($plugin, $formdata)) {
- print_error($plugin->get_error());
- return false;
- }
- }
- foreach ($this->feedbackplugins as $plugin) {
- if (!$this->update_plugin_instance($plugin, $formdata)) {
- print_error($plugin->get_error());
- return false;
- }
- }
- // update the database record
- // update all the calendar events
- $this->update_calendar($this->get_course_module()->id);
- $this->update_gradebook(false, $this->get_course_module()->id);
- $update = new stdClass();
- $update->id = $this->get_instance()->id;
- $update->nosubmissions = (!$this->is_any_submission_plugin_enabled()) ? 1: 0;
- $DB->update_record('assign', $update);
- return $result;
- }
- /**
- * add elements in grading plugin form
- *
- * @param mixed $grade stdClass|null
- * @param MoodleQuickForm $mform
- * @param stdClass $data
- * @return void
- */
- private function add_plugin_grade_elements($grade, MoodleQuickForm $mform, stdClass $data) {
- foreach ($this->feedbackplugins as $plugin) {
- if ($plugin->is_enabled() && $plugin->is_visible()) {
- $mform->addElement('header', 'header_' . $plugin->get_type(), $plugin->get_name());
- if (!$plugin->get_form_elements($grade, $mform, $data)) {
- $mform->removeElement('header_' . $plugin->get_type());
- }
- }
- }
- }
- /**
- * Add one plugins settings to edit plugin form
- *
- * @param assign_plugin $plugin The plugin to add the settings from
- * @param MoodleQuickForm $mform The form to add the configuration settings to. This form is modified directly (not returned)
- * @return void
- */
- private function add_plugin_settings(assign_plugin $plugin, MoodleQuickForm $mform) {
- global $CFG;
- if ($plugin->is_visible()) {
- // enabled
- //tied disableIf rule to this select element
- $mform->addElement('selectyesno', $plugin->get_subtype() . '_' . $plugin->get_type() . '_enabled', $plugin->get_name());
- $mform->addHelpButton($plugin->get_subtype() . '_' . $plugin->get_type() . '_enabled', 'enabled', $plugin->get_subtype() . '_' . $plugin->get_type());
- $default = get_config($plugin->get_subtype() . '_' . $plugin->get_type(), 'default');
- if ($plugin->get_config('enabled') !== false) {
- $default = $plugin->is_enabled();
- }
- $mform->setDefault($plugin->get_subtype() . '_' . $plugin->get_type() . '_enabled', $default);
- $plugin->get_settings($mform);
- }
- }
- /**
- * Add settings to edit plugin form
- *
- * @param MoodleQuickForm $mform The form to add the configuration settings to. This form is modified directly (not returned)
- * @return void
- */
- public function add_all_plugin_settings(MoodleQuickForm $mform) {
- $mform->addElement('header', 'general', get_string('submissionsettings', 'assign'));
- foreach ($this->submissionplugins as $plugin) {
- $this->add_plugin_settings($plugin, $mform);
- }
- $mform->addElement('header', 'general', get_string('feedbacksettings', 'assign'));
- foreach ($this->feedbackplugins as $plugin) {
- $this->add_plugin_settings($plugin, $mform);
- }
- }
- /**
- * Allow each plugin an opportunity to update the defaultvalues
- * passed in to the settings form (needed to set up draft areas for
- * editor and filemanager elements)
- * @param array $defaultvalues
- */
- public function plugin_data_preprocessing(&$defaultvalues) {
- foreach ($this->submissionplugins as $plugin) {
- if ($plugin->is_visible()) {
- $plugin->data_preprocessing($defaultvalues);
- }
- }
- foreach ($this->feedbackplugins as $plugin) {
- if ($plugin->is_visible()) {
- $plugin->data_preprocessing($defaultvalues);
- }
- }
- }
- /**
- * Get the name of the current module.
- *
- * @return string the module name (Assignment)
- */
- protected function get_module_name() {
- if (isset(self::$modulename)) {
- return self::$modulename;
- }
- self::$modulename = get_string('modulename', 'assign');
- return self::$modulename;
- }
- /**
- * Get the plural name of the current module.
- *
- * @return string the module name plural (Assignments)
- */
- protected function get_module_name_plural() {
- if (isset(self::$modulenameplural)) {
- return self::$modulenameplural;
- }
- self::$modulenameplural = get_string('modulenameplural', 'assign');
- return self::$modulenameplural;
- }
- /**
- * Has this assignment been constructed from an instance?
- *
- * @return bool
- */
- public function has_instance() {
- return $this->instance || $this->get_course_module();
- }
- /**
- * Get the settings for the current instance of this assignment
- *
- * @return stdClass The settings
- */
- public function get_instance() {
- global $DB;
- if ($this->instance) {
- return $this->instance;
- }
- if ($this->get_course_module()) {
- $this->instance = $DB->get_record('assign', array('id' => $this->get_course_module()->instance), '*', MUST_EXIST);
- }
- if (!$this->instance) {
- throw new coding_exception('Improper use of the assignment class. Cannot load the assignment record.');
- }
- return $this->instance;
- }
- /**
- * Get the context of the current course
- * @return mixed context|null The course context
- */
- public function get_course_context() {
- if (!$this->context && !$this->course) {
- throw new coding_exception('Improper use of the assignment class. Cannot load the course context.');
- }
- if ($this->context) {
- return $this->context->get_course_context();
- } else {
- return context_course::instance($this->course->id);
- }
- }
- /**
- * Get the current course module
- *
- * @return mixed stdClass|null The course module
- */
- public function get_course_module() {
- if ($this->coursemodule) {
- return $this->coursemodule;
- }
- if (!$this->context) {
- return null;
- }
- if ($this->context->contextlevel == CONTEXT_MODULE) {
- $this->coursemodule = get_coursemodule_from_id('assign', $this->context->instanceid, 0, false, MUST_EXIST);
- return $this->coursemodule;
- }
- return null;
- }
- /**
- * Get context module
- *
- * @return context
- */
- public function get_context() {
- return $this->context;
- }
- /**
- * Get the current course
- * @return mixed stdClass|null The course
- */
- public function get_course() {
- global $DB;
- if ($this->course) {
- return $this->course;
- }
- if (!$this->context) {
- return null;
- }
- $this->course = $DB->get_record('course', array('id' => $this->get_course_context()->instanceid), '*', MUST_EXIST);
- return $this->course;
- }
- /**
- * Return a grade in user-friendly form, whether it's a scale or not
- *
- * @param mixed $grade int|null
- * @param boolean $editing Are we allowing changes to this grade?
- * @param int $userid The user id the grade belongs to
- * @param int $modified Timestamp from when the grade was last modified
- * @return string User-friendly representation of grade
- */
- public function display_grade($grade, $editing, $userid=0, $modified=0) {
- global $DB;
- static $scalegrades = array();
- if ($this->get_instance()->grade >= 0) {
- // Normal number
- if ($editing && $this->get_instance()->grade > 0) {
- if ($grade < 0) {
- $displaygrade = '';
- } else {
- $displaygrade = format_float($grade);
- }
- $o = '<input type="text" name="quickgrade_' . $userid . '" value="' . $displaygrade . '" size="6" maxlength="10" class="quickgrade"/>';
- $o .= ' / ' . format_float($this->get_instance()->grade,2);
- $o .= '<input type="hidden" name="grademodified_' . $userid . '" value="' . $modified . '"/>';
- return $o;
- } else {
- if ($grade == -1 || $grade === null) {
- return '-';
- } else {
- return format_float(($grade),2) .' / '. format_float($this->get_instance()->grade,2);
- }
- }
- } else {
- // Scale
- if (empty($this->cache['scale'])) {
- if ($scale = $DB->get_record('scale', array('id'=>-($this->get_instance()->grade)))) {
- $this->cache['scale'] = make_menu_from_list($scale->scale);
- } else {
- return '-';
- }
- }
- if ($editing) {
- $o = '<select name="quickgrade_' . $userid . '" class="quickgrade">';
- $o .= '<option value="-1">' . get_string('nograde') . '</option>';
- foreach ($this->cache['scale'] as $optionid => $option) {
- $selected = '';
- if ($grade == $optionid) {
- $selected = 'selected="selected"';
- }
- $o .= '<option value="' . $optionid . '" ' . $selected . '>' . $option . '</option>';
- }
- $o .= '</select>';
- $o .= '<input type="hidden" name="grademodified_' . $userid . '" value="' . $modified . '"/>';
- return $o;
- } else {
- $scaleid = (int)$grade;
- if (isset($this->cache['scale'][$scaleid])) {
- return $this->cache['scale'][$scaleid];
- }
- return '-';
- }
- }
- }
- /**
- * Load a list of users enrolled in the current course with the specified permission and group (0 for no group)
- *
- * @param int $currentgroup
- * @param bool $idsonly
- * @return array List of user records
- */
- public function list_participants($currentgroup, $idsonly) {
- if ($idsonly) {
- return get_enrolled_users($this->context, "mod/assign:submit", $currentgroup, 'u.id');
- } else {
- return get_enrolled_users($this->context, "mod/assign:submit", $currentgroup);
- }
- }
- /**
- * Load a count of users enrolled in the current course with the specified permission and group (0 for no group)
- *
- * @param int $currentgroup
- * @return int number of matching users
- */
- public function count_participants($currentgroup) {
- return count_enrolled_users($this->context, "mod/assign:submit", $currentgroup);
- }
- /**
- * Load a count of users enrolled in the current course with the specified permission and group (optional)
- *
- * @param string $status The submission status - should match one of the constants
- * @return int number of matching submissions
- */
- public function count_submissions_with_status($status) {
- global $DB;
- return $DB->count_records_sql("SELECT COUNT('x')
- FROM {assign_submission}
- WHERE assignment = ? AND
- status = ?", array($this->get_course_module()->instance, $status));
- }
- /**
- * Utility function to get the userid for every row in the grading table
- * so the order can be frozen while we iterate it
- *
- * @return array An array of userids
- */
- private function get_grading_userid_list(){
- $filter = get_user_preferences('assign_filter', '');
- $table = new assign_grading_table($this, 0, $filter, 0, false);
- $useridlist = $table->get_column_data('userid');
- return $useridlist;
- }
- /**
- * Utility function get the userid based on the row number of the grading table.
- * This takes into account any active filters on the table.
- *
- * @param int $num The row number of the user
- * @param bool $last This is set to true if this is the last user in the table
- * @return mixed The user id of the matching user or false if there was an error
- */
- private function get_userid_for_row($num, $last){
- if (!array_key_exists('userid_for_row', $this->cache)) {
- $this->cache['userid_for_row'] = array();
- }
- if (array_key_exists($num, $this->cache['userid_for_row'])) {
- list($userid, $last) = $this->cache['userid_for_row'][$num];
- return $userid;
- }
- $filter = get_user_preferences('assign_filter', '');
- $table = new assign_grading_table($this, 0, $filter, 0, false);
- $userid = $table->get_cell_data($num, 'userid', $last);
- $this->cache['userid_for_row'][$num] = array($userid, $last);
- return $userid;
- }
- /**
- * Return all assignment submissions by ENROLLED students (even empty)
- *
- * @param string $sort optional field names for the ORDER BY in the sql query
- * @param string $dir optional specifying the sort direction, defaults to DESC
- * @return array The submission objects indexed by id
- */
- private function get_all_submissions( $sort="", $dir="DESC") {
- global $CFG, $DB;
- if ($sort == "lastname" or $sort == "firstname") {
- $sort = "u.$sort $dir";
- } else if (empty($sort)) {
- $sort = "a.timemodified DESC";
- } else {
- $sort = "a.$sort $dir";
- }
- return $DB->get_records_sql("SELECT a.*
- FROM {assign_submission} a, {user} u
- WHERE u.id = a.userid
- AND a.assignment = ?
- ORDER BY $sort", array($this->get_instance()->id));
- }
- /**
- * Generate zip file from array of given files
- *
- * @param array $filesforzipping - array of files to pass into archive_to_pathname - this array is indexed by the final file name and each element in the array is an instance of a stored_file object
- * @return path of temp file - note this returned file does not have a .zip extension - it is a temp file.
- */
- private function pack_files($filesforzipping) {
- global $CFG;
- //create path for new zip file.
- $tempzip = tempnam($CFG->tempdir.'/', 'assignment_');
- //zip files
- $zipper = new zip_packer();
- if ($zipper->archive_to_pathname($filesforzipping, $tempzip)) {
- return $tempzip;
- }
- return false;
- }
- /**
- * Finds all assignment notifications that have yet to be mailed out, and mails them.
- *
- * Cron function to be run periodically according to the moodle cron
- *
- * @return bool
- */
- static function cron() {
- global $DB;
- // only ever send a max of one days worth of updates
- $yesterday = time() - (24 * 3600);
- $timenow = time();
- // Collect all submissions from the past 24 hours that require mailing.
- $sql = "SELECT s.*, a.course, a.name, g.*, g.id as gradeid, g.timemodified as lastmodified
- FROM {assign} a
- JOIN {assign_grades} g ON g.assignment = a.id
- LEFT JOIN {assign_submission} s ON s.assignment = a.id AND s.userid = g.userid
- WHERE g.timemodified >= :yesterday AND
- g.timemodified <= :today AND
- g.mailed = 0";
- $params = array('yesterday' => $yesterday, 'today' => $timenow);
- $submissions = $DB->get_records_sql($sql, $params);
- if (empty($submissions)) {
- mtrace('done.');
- return true;
- }
- mtrace('Processing ' . count($submissions) . ' assignment submissions ...');
- // Preload courses we are going to need those.
- $courseids = array();
- foreach ($submissions as $submission) {
- $courseids[] = $submission->course;
- }
- // Filter out duplicates
- $courseids = array_unique($courseids);
- $ctxselect = context_helper::get_preload_record_columns_sql('ctx');
- list($courseidsql, $params) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
- $sql = "SELECT c.*, {$ctxselect}
- FROM {course} c
- LEFT JOIN {context} ctx ON ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel
- WHERE c.id {$courseidsql}";
- $params['contextlevel'] = CONTEXT_COURSE;
- $courses = $DB->get_records_sql($sql, $params);
- // Clean up... this could go on for a while.
- unset($courseids);
- unset($ctxselect);
- unset($courseidsql);
- unset($params);
- // Simple array we'll use for caching modules.
- $modcache = array();
- // Message students about new feedback
- foreach ($submissions as $submission) {
- mtrace("Processing assignment submission $submission->id ...");
- // do not cache user lookups - could be too many
- if (!$user = $DB->get_record("user", array("id"=>$submission->userid))) {
- mtrace("Could not find user $submission->userid");
- continue;
- }
- // use a cache to prevent the same DB queries happening over and over
- if (!array_key_exists($submission->course, $courses)) {
- mtrace("Could not find course $submission->course");
- continue;
- }
- $course = $courses[$submission->course];
- if (isset($course->ctxid)) {
- // Context has not yet been preloaded. Do so now.
- context_helper::preload_from_record($course);
- }
- // Override the language and timezone of the "current" user, so that
- // mail is customised for the receiver.
- cron_setup_user($user, $course);
- // context lookups are already cached
- $coursecontext = context_course::instance($course->id);
- if (!is_enrolled($coursecontext, $user->id)) {
- $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
- mtrace(fullname($user)." not an active participant in " . $courseshortname);
- continue;
- }
- if (!$grader = $DB->get_record("user", array("id"=>$submission->grader))) {
- mtrace("Could not find grader $submission->grader");
- continue;
- }
- if (!array_key_exists($submission->assignment, $modcache)) {
- if (! $mod = get_coursemodule_from_instance("assign", $submission->assignment, $course->id)) {
- mtrace("Could not find course module for assignment id $submission->assignment");
- continue;
- }
- $modcache[$submission->assignment] = $mod;
- } else {
- $mod = $modcache[$submission->assignment];
- }
- // context lookups are already cached
- $contextmodule = context_module::instance($mod->id);
- if (!$mod->visible) {
- // Hold mail notification for hidden assignments until later
- continue;
- }
- // need to send this to the student
- $messagetype = 'feedbackavailable';
- $eventtype = 'assign_notification';
- $updatetime = $submission->lastmodified;
- $modulename = get_string('modulename', 'assign');
- self::send_assignment_notification($grader, $user, $messagetype, $eventtype, $updatetime, $mod, $contextmodule, $course, $modulename, $submission->name);
- $grade = new stdClass();
- $grade->id = $submission->gradeid;
- $grade->mailed = 1;
- $DB->update_record('assign_grades', $grade);
- mtrace('Done');
- }
- mtrace('Done processing ' . count($submissions) . ' assignment submissions');
- cron_setup_user();
- // Free up memory just to be sure
- unset($courses);
- unset($modcache);
- return true;
- }
- /**
- * Update a grade in the grade table for the assignment and in the gradebook
- *
- * @param stdClass $grade a grade record keyed on id
- * @return bool true for success
- */
- private function update_grade($grade) {
- global $DB;
- $grade->timemodified = time();
- if ($grade->grade && $grade->grade != -1) {
- if ($this->get_instance()->grade > 0) {
- if (!is_numeric($grade->grade)) {
- return false;
- } else if ($grade->grade > $this->get_instance()->grade) {
- return false;
- } else if ($grade->grade < 0) {
- return false;
- }
- } else {
- // this is a scale
- if ($scale = $DB->get_record('scale', array('id' => -($this->get_instance()->grade)))) {
- $scaleoptions = make_menu_from_list($scale->scale);
- if (!array_key_exists((int) $grade->grade, $scaleoptions)) {
- return false;
- }
- }
- }
- }
- $result = $DB->update_record('assign_grades', $grade);
- if ($result) {
- $this->gradebook_item_update(null, $grade);
- }
- return $result;
- }
- /**
- * display the submission that is used by a plugin
- * Uses url parameters 'sid', 'gid' and 'plugin'
- * @param string $pluginsubtype
- * @return string
- */
- private function view_plugin_content($pluginsubtype) {
- global $USER;
- $o = '';
- $submissionid = optional_param('sid', 0, PARAM_INT);
- $gradeid = optional_param('gid', 0, PARAM_INT);
- $plugintype = required_param('plugin', PARAM_TEXT);
- $item = null;
- if ($pluginsubtype == 'assignsubmission') {
- $plugin = $this->get_submission_plugin_by_type($plugintype);
- if ($submissionid <= 0) {
- throw new coding_exception('Submission id should not be 0');
- }
- $item = $this->get_submission($submissionid);
- // permissions
- if ($item->userid != $USER->id) {
- require_capability('mod/assign:grade', $this->context);
- }
- $o .= $this->output->render(new assign_header($this->get_instance(),
- $this->get_context(),
- $this->show_intro(),
- $this->get_course_module()->id,
- $plugin->get_name()));
- $o .= $this->output->render(new assign_submission_plugin_submission($plugin,
- $item,
- assign_submission_plugin_submission::FULL,
- $this->get_course_module()->id,
- $this->get_return_action(),
- $this->get_return_params()));
- $this->add_to_log('view submission', get_string('viewsubmissionforuser', 'assign', $item->userid));
- } else {
- $plugin = $this->get_feedback_plugin_by_type($plugintype);
- if ($gradeid <= 0) {
- throw new coding_exception('Grade id should not be 0');
- }
- $item = $this->get_grade($gradeid);
- // permissions
- if ($item->userid != $USER->id) {
- require_capability('mod/assign:grade', $this->context);
- }
- $o .= $this->output->render(new assign_header($this->get_instance(),
- $this->get_context(),
- $this->show_intro(),
- $this->get_course_module()->id,
- $plugin->get_name()));
- $o .= $this->output->render(new assign_feedback_plugin_feedback($plugin,
- $item,
- assign_feedback_plugin_feedback::FULL,
- $this->get_course_module()->id,
- $this->get_return_action(),
- $this->get_return_params()));
- $this->add_to_log('view feedback', get_string('viewfeedbackforuser', 'assign', $item->userid));
- }
- $o .= $this->view_return_links();
- $o .= $this->view_footer();
- return $o;
- }
- /**
- * render the content in editor that is often used by plugin
- *
- * @param string $filearea
- * @param int $submissionid
- * @param string $plugintype
- * @param string $editor
- * @param string $component
- * @return string
- */
- public function render_editor_content($filearea, $submissionid, $plugintype, $editor, $component) {
- global $CFG;
- $result = '';
- $plugin = $this->get_submission_plugin_by_type($plugintype);
- $text = $plugin->get_editor_text($editor, $submissionid);
- $format = $plugin->get_editor_format($editor, $submissionid);
- $finaltext = file_rewrite_pluginfile_urls($text, 'pluginfile.php', $this->get_context()->id, $component, $filearea, $submissionid);
- $result .= format_text($finaltext, $format, array('overflowdiv' => true, 'context' => $this->get_context()));
- if ($CFG->enableportfolios) {
- require_once($CFG->libdir . '/portfoliolib.php');
- $button = new portfolio_add_button();
- $button->set_callback_options('assiā¦
Large files files are truncated, but you can click here to view the full file