From 0dc47fb913c2bfa0bab22da98101dfd328b7da3b Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Mon, 4 Jan 2010 17:48:20 +0000 Subject: [PATCH] MDL-19941 Submission attachments and embedded files draft support Plus some cleaning up here and there --- mod/workshop/editform.php | 22 ++-- mod/workshop/fileinfolib.php | 109 +++++++++++++++++++ mod/workshop/lang/en_utf8/workshop.php | 10 +- mod/workshop/lib.php | 141 +++++++++++++++++++++++-- mod/workshop/locallib.php | 25 ++--- mod/workshop/styles.php | 7 +- mod/workshop/submission.php | 88 ++++++--------- mod/workshop/submission_form.php | 10 +- 8 files changed, 307 insertions(+), 105 deletions(-) create mode 100644 mod/workshop/fileinfolib.php diff --git a/mod/workshop/editform.php b/mod/workshop/editform.php index 976b074c4d..12ab1b889c 100644 --- a/mod/workshop/editform.php +++ b/mod/workshop/editform.php @@ -28,27 +28,17 @@ require_once(dirname(__FILE__).'/locallib.php'); $cmid = required_param('cmid', PARAM_INT); // course module id -if (!$cm = get_coursemodule_from_id('workshop', $cmid)) { - print_error('invalidcoursemodule'); -} - -if (!$course = $DB->get_record('course', array('id' => $cm->course))) { - print_error('coursemisconf'); -} +$cm = get_coursemodule_from_id('workshop', $cmid, 0, false, MUST_EXIST); +$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); require_login($course, false, $cm); - -$context = $PAGE->context; - if (isguestuser()) { - print_error('err_noguests', 'workshop', "$CFG->wwwroot/mod/workshop/view.php?id=$cmid"); -} - -if (!$workshop = $DB->get_record('workshop', array('id' => $cm->instance))) { - print_error('err_invalidworkshopid', 'workshop'); + print_error('guestnoedit', 'workshop', "$CFG->wwwroot/mod/workshop/view.php?id=$cmid"); } +require_capability('mod/workshop:editdimensions', $PAGE->context); -$workshop = new workshop_api($workshop, $cm, $course); +$workshop = $DB->get_record('workshop', array('id' => $cm->instance), '*', MUST_EXIST); +$workshop = new workshop_api($workshop, $cm, $course); // where should the user be sent after closing the editing form $returnurl = "{$CFG->wwwroot}/mod/workshop/view.php?id={$cm->id}"; diff --git a/mod/workshop/fileinfolib.php b/mod/workshop/fileinfolib.php new file mode 100644 index 0000000000..fe41d9656b --- /dev/null +++ b/mod/workshop/fileinfolib.php @@ -0,0 +1,109 @@ +. + +/** + * Defines workshop_file_info class + * + * @package mod-workshop + * @copyright 2009 David Mudrak + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Represents the nodes of the virtual directory tree that may be browsed in file manager + * + * Here we create a virtual hierarchy of all submissions, sorted by their author. + */ +class workshop_file_info extends file_info { + protected $course; + protected $cm; + protected $areas; + protected $filearea; + + public function __construct($browser, $course, $cm, $context, $areas, $filearea) { + parent::__construct($browser, $context); + $this->course = $course; + $this->cm = $cm; + $this->areas = $areas; + $this->filearea = $filearea; + } + + /** + * Returns list of standard virtual file/directory identification. + * The difference from stored_file parameters is that null values + * are allowed in all fields + * @return array with keys contextid, filearea, itemid, filepath and filename + */ + public function get_params() { + return array('contextid'=>$this->context->id, + 'filearea' =>$this->filearea, + 'itemid' =>null, + 'filepath' =>null, + 'filename' =>null); + } + + /** + * Returns localised visible name. + * @return string + */ + public function get_visible_name() { + return $this->areas[$this->filearea]; + } + + /** + * Can I add new files or directories? + * @return bool + */ + public function is_writable() { + return false; + } + + /** + * Is directory? + * @return bool + */ + public function is_directory() { + return true; + } + + /** + * Returns list of children. + * @return array of file_info instances + */ + public function get_children() { + global $DB; + + $children = array(); + $itemids = $DB->get_records('files', array('contextid' => $this->context->id, 'filearea' => $this->filearea), 'itemid', "DISTINCT itemid"); + foreach ($itemids as $itemid => $unused) { + if ($child = $this->browser->get_file_info($this->context, $this->filearea, $itemid)) { + $children[] = $child; + } + } + return $children; + } + + /** + * Returns parent file_info instance + * @return file_info or null for root + */ + public function get_parent() { + return $this->browser->get_file_info($this->context); + } +} diff --git a/mod/workshop/lang/en_utf8/workshop.php b/mod/workshop/lang/en_utf8/workshop.php index 52f18014ae..d9e1c4837c 100644 --- a/mod/workshop/lang/en_utf8/workshop.php +++ b/mod/workshop/lang/en_utf8/workshop.php @@ -25,10 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$string['numofrandomlyallocatedsubmissions'] = 'Randomly allocating $a submissions'; -$string[''] = ''; -$string[''] = ''; -$string[''] = ''; $string[''] = ''; $string[''] = ''; $string[''] = ''; @@ -63,6 +59,8 @@ $string['allocationrandom'] = 'Random allocation'; $string['allocationsettings'] = 'Allocation settings'; $string['allocation'] = 'Submission allocation'; $string['allocationview'] = 'View current allocations'; +$string['areasubmissionattachment'] = 'Submission attachments'; +$string['areasubmissioncontent'] = 'Submission texts'; $string['areyousuretodeallocate'] = 'Are you sure you want deallocate the selected assessment?'; $string['areyousuretodeallocategraded'] = 'You are going to remove the assessment that has already been graded. Are you really sure you want to do it?'; $string['assessallexamples'] = 'Assess all examples'; @@ -129,8 +127,10 @@ $string['nogradeyet'] = 'No grade yet'; $string['nosubmissionfound'] = 'No submission found for this user'; $string['nosubmissions'] = 'No submissions yet in this workshop'; $string['nothingtoreview'] = 'Nothing to review'; +$string['noworkshops'] = 'There are no workshops in this course'; $string['nsassessments'] = 'Number of required assessments of other users\' work'; $string['numofdeallocatedassessment'] = 'Deallocating $a assessment(s)'; +$string['numofrandomlyallocatedsubmissions'] = 'Randomly allocating $a submissions'; $string['numofreviews'] = 'Number of reviews'; $string['numofselfallocatedsubmissions'] = 'Self-allocating $a submission(s)'; $string['numperauthor'] = 'per submission'; @@ -153,7 +153,7 @@ $string['strategynoerrors'] = 'Number of errors'; $string['strategynograding'] = 'No grading'; $string['strategyrubric'] = 'Rubric grading'; $string['submissionattachment'] = 'Attachment'; -$string['submissiondata'] = 'Submission data'; +$string['submissioncontent'] = 'Submission content'; $string['submissionend'] = 'End of submission phase'; $string['submissionsettings'] = 'Submission settings'; $string['submissionstart'] = 'Start of submission phase'; diff --git a/mod/workshop/lib.php b/mod/workshop/lib.php index 9c8d0ebd0b..4f1fe1c564 100644 --- a/mod/workshop/lib.php +++ b/mod/workshop/lib.php @@ -307,6 +307,140 @@ function workshop_supports($feature) { } } +/** + * Returns all other caps used in the module + * + * @return array + */ +function workshop_get_extra_capabilities() { + return array('moodle/site:accessallgroups'); +} + +//////////////////////////////// +/// File API /////////////////// +//////////////////////////////// + +/** + * Serves the submission attachments + * + * The access rights to the file are checked here. + * + * @param object $course + * @param object $cminfo + * @param object $context + * @param string $filearea + * @param array $args + * @param bool $forcedownload + * @return bool false if file not found, does not return if found - justsend the file + */ +function workshop_pluginfile($course, $cminfo, $context, $filearea, $args, $forcedownload) { + global $DB; + + if (!$cminfo->uservisible) { + return false; + } + + $fileareas = array('workshop_submission_content', 'workshop_submission_attachment'); + if (!in_array($filearea, $fileareas)) { + return false; + } + + $submissionid = (int)array_shift($args); + + if (!$cm = get_coursemodule_from_instance('workshop', $cminfo->instance, $course->id)) { + return false; + } + + require_course_login($course, true, $cm); + + if (!$submission = $DB->get_record('workshop_submissions', array('id' => $submissionid))) { + return false; + } + + if (!$workshop = $DB->get_record('workshop', array('id' => $cminfo->instance))) { + return false; + } + + $fs = get_file_storage(); + $relativepath = '/' . implode('/', $args); + $fullpath = $context->id . $filearea . $submissionid . $relativepath; + if ((!$file = $fs->get_file_by_hash(sha1($fullpath))) || ($file->is_directory())) { + return false; + } + // TODO MDL-19941 make sure the user is allowed to see the submission + + // finally send the file + send_stored_file($file, 0, 0, true); // download MUST be forced - security! +} + +/** + * Returns the lists of all browsable file areas within the given module context + * + * The file area workshop_intro for the activity introduction field is added automatically + * by {@link file_browser::get_file_info_module()} + * + * @param object $course + * @param object $cm + * @param object $context + * @return array of [(string)filearea] => (string)description + */ +function workshop_get_file_areas($course, $cm, $context) { + $areas = array(); + // todo re-think capability checking + if (has_capability('mod/workshop:submit', $context) || has_capability('mod/workshop:submitexamples', $context)) { + $areas['workshop_submission_content'] = get_string('areasubmissioncontent', 'workshop'); + $areas['workshop_submission_attachment'] = get_string('areasubmissionattachment', 'workshop'); + } + return $areas; +} + +/** + * File browsing support for workshop file areas + * + * @param object $browser + * @param object $areas + * @param object $course + * @param object $cm + * @param object $context + * @param string $filearea + * @param int $itemid + * @param string $filepath + * @param string $filename + * @return object file_info instance or null if not found + */ +function workshop_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) { + global $CFG, $DB; + static $authors=null; // cache for submission authors + + if (!($filearea == 'workshop_submission_content' || $filearea == 'workshop_submission_attachment')) { + return null; + } + if (is_null($itemid)) { + require_once($CFG->dirroot . '/mod/workshop/fileinfolib.php'); + return new workshop_file_info($browser, $course, $cm, $context, $areas, $filearea); + } + + $fs = get_file_storage(); + $filepath = is_null($filepath) ? '/' : $filepath; + $filename = is_null($filename) ? '.' : $filename; + if (!$storedfile = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) { + return null; + } + + if (is_null($authors)) { + $sql = 'SELECT s.id, u.lastname, u.firstname + FROM {workshop_submissions} s + JOIN {user} u ON (s.userid = u.id) + WHERE s.workshopid = ?'; + $params[0] = $cm->instance; + $authors = $DB->get_records_sql($sql, $params); + } + $urlbase = $CFG->wwwroot . '/pluginfile.php'; + $topvisiblename = fullname($authors[$itemid]); + // do not allow manual modification of any files! + return new file_info_stored($browser, $context, $storedfile, $urlbase, $topvisiblename, true, true, false, false); +} + //////////////////////////////////////////////////////////////////////////////// // Other functions needed by Moodle core follows. They can't be put into // // locallib.php because they are used by some core scripts (like modedit.php) // @@ -324,7 +458,6 @@ function workshop_supports($feature) { * @return array Array of integers */ function workshop_get_maxgrades() { - $grades = array(); for ($i=100; $i>=0; $i--) { $grades[$i] = $i; @@ -340,7 +473,6 @@ function workshop_get_maxgrades() { * @return array Array of integers */ function workshop_get_numbers_of_assessments() { - $options = array(); $options[30] = 30; $options[20] = 20; @@ -357,7 +489,6 @@ function workshop_get_numbers_of_assessments() { * @return array Array of integers 0, 1, 2, ..., 10 */ function workshop_get_teacher_weights() { - $weights = array(); for ($i=10; $i>=0; $i--) { $weights[$i] = $i; @@ -371,7 +502,6 @@ function workshop_get_teacher_weights() { * @return array Array of integers 0, 1, 2, ..., 16 */ function workshop_get_dimension_weights() { - $weights = array(); for ($i=16; $i>=0; $i--) { $weights[$i] = $i; @@ -386,7 +516,6 @@ function workshop_get_dimension_weights() { * $return array Array ['string' => 'string'] */ function workshop_get_strategies() { - $installed = get_list_of_plugins('mod/workshop/grading'); $forms = array(); foreach ($installed as $strategy) { @@ -402,7 +531,6 @@ function workshop_get_strategies() { * @return array Array 'mode DB code'=>'mode name' */ function workshop_get_example_modes() { - $modes = array(); $modes[WORKSHOP_EXAMPLES_VOLUNTARY] = get_string('examplesvoluntary', 'workshop'); $modes[WORKSHOP_EXAMPLES_BEFORE_SUBMISSION] = get_string('examplesbeforesubmission', 'workshop'); @@ -427,7 +555,6 @@ function workshop_get_example_modes() { * @return array Array of objects */ function workshop_get_comparison_levels() { - $levels = array(); $levels[WORKSHOP_COMPARISON_VERYHIGH] = new stdClass; diff --git a/mod/workshop/locallib.php b/mod/workshop/locallib.php index e4dbec8e50..2d17ada78c 100644 --- a/mod/workshop/locallib.php +++ b/mod/workshop/locallib.php @@ -52,10 +52,10 @@ class workshop_api extends workshop { * @param object $instance The instance data row from {workshop} table * @param object $cm Course module record * @param object $courserecord Course record + */ public function __construct($instance, $cm, $courserecord) { parent::__construct($instance, $cm, $courserecord); } - */ /** * Fetches all users with the capability mod/workshop:submit in the current context @@ -232,7 +232,7 @@ class workshop_api extends workshop { if ($examples === true) { $sql .= ' AND example = 1'; } - if (is_int($userid)) { + if (is_numeric($userid)) { $sql .= ' AND userid = ?'; $params = array_merge($params, array($userid)); } @@ -260,7 +260,7 @@ class workshop_api extends workshop { return false; } $rs = $this->get_submissions_recordset($id, false); - if (is_int($id)) { + if (is_numeric($id)) { $submission = $rs->current(); $rs->close(); if (empty($submission->id)) { @@ -309,16 +309,16 @@ class workshop_api extends workshop { INNER JOIN {user} author ON (s.userid = author.id) WHERE s.workshopid = ?'; $params = array($this->id); - if (is_int($reviewerid)) { - $sql .= ' AND reviewerid = ?'; + if (is_numeric($reviewerid)) { + $sql .= ' AND reviewer.id = ?'; $params = array_merge($params, array($reviewerid)); } if (is_array($reviewerid)) { list($usql, $uparams) = $DB->get_in_or_equal($reviewerid); - $sql .= ' AND reviewerid ' . $usql; + $sql .= ' AND reviewer.id ' . $usql; $params = array_merge($params, $uparams); } - if (is_int($id)) { + if (is_numeric($id)) { $sql .= ' AND a.id = ?'; $params = array_merge($params, array($id)); } @@ -489,28 +489,22 @@ class workshop_api extends workshop { /** * Returns instance of grading strategy class * - * @param object $workshop Workshop record * @return object Instance of a grading strategy */ public function grading_strategy_instance() { - if (!($this->strategy === clean_param($workshop->strategy, PARAM_ALPHA))) { - throw new moodle_workshop_exception($this, 'invalidstrategyname'); - } - if (is_null($this->strategy_api)) { - $strategylib = dirname(__FILE__) . '/grading/' . $workshop->strategy . '/strategy.php'; + $strategylib = dirname(__FILE__) . '/grading/' . $this->strategy . '/strategy.php'; if (is_readable($strategylib)) { require_once($strategylib); } else { throw new moodle_workshop_exception($this, 'missingstrategy'); } - $classname = 'workshop_' . $workshop->strategy . '_strategy'; + $classname = 'workshop_' . $this->strategy . '_strategy'; $this->strategy_api = new $classname($this); if (!in_array('workshop_strategy', class_implements($this->strategy_api))) { throw new moodle_workshop_exception($this, 'strategynotimplemented'); } } - return $this->strategy_api; } @@ -579,4 +573,3 @@ class moodle_workshop_exception extends moodle_exception { parent::__construct($errorcode, $module, $link, $a, $debuginfo); } } - diff --git a/mod/workshop/styles.php b/mod/workshop/styles.php index 41dfce2a33..7ae5de33a7 100644 --- a/mod/workshop/styles.php +++ b/mod/workshop/styles.php @@ -120,4 +120,9 @@ margin-top: 1em; } - +/** + * Assessment + */ +.assessmentform .description { + margin: 0px 1em; +} diff --git a/mod/workshop/submission.php b/mod/workshop/submission.php index 0ff7fe06af..bb808cee94 100644 --- a/mod/workshop/submission.php +++ b/mod/workshop/submission.php @@ -31,101 +31,79 @@ require_once(dirname(__FILE__).'/submission_form.php'); $cmid = required_param('cmid', PARAM_INT); // course module id $id = optional_param('id', 0, PARAM_INT); // submission id -if (!$cm = get_coursemodule_from_id('workshop', $cmid)) { - print_error('invalidcoursemodule'); -} - -if (!$course = $DB->get_record('course', array('id' => $cm->course))) { - print_error('coursemisconf'); -} +$cm = get_coursemodule_from_id('workshop', $cmid, 0, false, MUST_EXIST); +$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); require_login($course, false, $cm); - -$context = get_context_instance(CONTEXT_MODULE, $cm->id); - if (isguestuser()) { print_error('guestnoedit', 'workshop', "$CFG->wwwroot/mod/workshop/view.php?id=$cmid"); } +require_capability('mod/workshop:submit', $PAGE->context); -if (!$workshop = $DB->get_record('workshop', array('id' => $cm->instance))) { - print_error('invalidid', 'workshop'); -} +$workshop = $DB->get_record('workshop', array('id' => $cm->instance), '*', MUST_EXIST); +$workshop = new workshop_api($workshop, $cm, $course); if ($id) { // submission is specified - if (!$submission = $DB->get_record('workshop_submissions', array('id' => $id, 'workshopid' => $workshop->id))) { - print_error('invalidsubmissionid', 'workshop'); - } - // todo check access rights - //require_capability('mod/workshop:submit', $context) or user has cap edit all submissions? - + $submission = $DB->get_record('workshop_submissions', array('id' => $id, 'workshopid' => $workshop->id), '*', MUST_EXIST); } else { // no submission specified - //todo require_capability('mod/workshop:submit', $context); - if (!$submission = workshop_get_user_submission($workshop, $USER->id)) { + if (!$submission = $workshop->get_submission_by_author($USER->id)) { $submission = new object(); $submission->id = null; } } unset($id); // not needed anymore -$maxfiles = $workshop->nattachments; -$maxbytes = $workshop->maxbytes; - -$dataoptions = array('trusttext' => true, 'subdirs' => false, 'maxfiles' => $maxfiles, 'maxbytes' => $maxbytes); -$attachmentoptions = array('subdirs' => false, 'maxfiles'=>$maxfiles, 'maxbytes'=>$maxbytes); - -$submission = file_prepare_standard_editor($submission, 'data', $dataoptions, $context, 'workshop_submission', $submission->id); -$submission = file_prepare_standard_filemanager($submission, 'attachment', $attachmentoptions, $context, - 'workshop_attachment', $submission->id); - -$submission->cmid = $cm->id; - +$maxfiles = $workshop->nattachments; +$maxbytes = $workshop->maxbytes; +$contentoptions = array('trusttext' => true, 'subdirs' => false, 'maxfiles' => $maxfiles, 'maxbytes' => $maxbytes); +$attachmentoptions = array('subdirs' => false, 'maxfiles'=>$maxfiles, 'maxbytes'=>$maxbytes); +$submission = file_prepare_standard_editor($submission, 'content', $contentoptions, $PAGE->context, + 'workshop_submission_content', $submission->id); +$submission = file_prepare_standard_filemanager($submission, 'attachment', $attachmentoptions, $PAGE->context, + 'workshop_submission_attachment', $submission->id); // create form and set initial data -$mform = new workshop_submission_form(null, array('current' => $submission, 'cm' => $cm, 'workshop'=>$workshop, - 'dataoptions' => $dataoptions, 'attachmentoptions'=>$attachmentoptions)); +$mform = new workshop_submission_form(null, array('current' => $submission, 'cm' => $cm, 'workshop' => $workshop, + 'contentoptions' => $contentoptions, 'attachmentoptions' => $attachmentoptions)); if ($mform->is_cancelled()) { redirect("view.php?id=$cm->id"); } else if ($submission = $mform->get_data()) { - $timenow = time(); - if (empty($submission->id)) { $submission->workshopid = $workshop->id; $submission->example = 0; // todo add examples support $submission->userid = $USER->id; $submission->timecreated = $timenow; } - $submission->timemodified = $timenow; $submission->title = trim($submission->title); - $submission->data = ''; // updated later - $submission->dataformat = FORMAT_HTML; // updated later - $submission->datatrust = 0; // updated later - + $submission->content = ''; // updated later + $submission->contentformat = FORMAT_HTML; // updated later + $submission->contenttrust = 0; // updated later if (empty($submission->id)) { $submission->id = $DB->insert_record('workshop_submissions', $submission); // todo add to log } - // save and relink embedded images and save attachments - $submission = file_postupdate_standard_editor($submission, 'data', $dataoptions, $context, - 'workshop_submission', $submission->id); - $submission = file_postupdate_standard_filemanager($submission, 'attachment', $attachmentoptions, $context, - 'workshop_attachment', $submission->id); - + $submission = file_postupdate_standard_editor($submission, 'content', $contentoptions, $PAGE->context, + 'workshop_submission_content', $submission->id); + $submission = file_postupdate_standard_filemanager($submission, 'attachment', $attachmentoptions, $PAGE->context, + 'workshop_submission_attachment', $submission->id); // store the updated values or re-save the new submission $DB->update_record('workshop_submissions', $submission); - redirect("view.php?id=$cm->id"); } -$stredit = empty($submission->id) ? get_string('editingsubmission', 'workshop') : get_string('edit'); +// Output starts here +$PAGE->set_url('mod/workshop/submission.php', array('cmid' => $cm->id)); +$PAGE->set_title($workshop->name); +$PAGE->set_heading($course->fullname); +$stredit = empty($submission->id) ? get_string('editingsubmission', 'workshop') : get_string('edit'); $navigation = build_navigation($stredit, $cm); -print_header_simple(format_string($workshop->name), "", $navigation, "", "", true, "", navmenu($course, $cm)); - -print_heading(format_string($workshop->name)); +$menu = navmenu($course, $cm); +echo $OUTPUT->header($navigation, $menu); +echo $OUTPUT->heading(format_string($workshop->name), 2); $mform->display(); - -print_footer($course); +echo $OUTPUT->footer(); diff --git a/mod/workshop/submission_form.php b/mod/workshop/submission_form.php index 41a356adb2..aab37f75dd 100644 --- a/mod/workshop/submission_form.php +++ b/mod/workshop/submission_form.php @@ -36,7 +36,7 @@ class workshop_submission_form extends moodleform { $current = $this->_customdata['current']; $workshop = $this->_customdata['workshop']; $cm = $this->_customdata['cm']; - $dataoptions = $this->_customdata['dataoptions']; + $contentoptions = $this->_customdata['contentoptions']; $attachmentoptions = $this->_customdata['attachmentoptions']; $mform->addElement('header', 'general', get_string('submission', 'workshop')); @@ -45,8 +45,8 @@ class workshop_submission_form extends moodleform { $mform->setType('title', PARAM_TEXT); $mform->addRule('title', null, 'required', null, 'client'); - $mform->addElement('editor', 'data_editor', get_string('submissiondata', 'workshop'), null, $dataoptions); - $mform->setType('data_editor', PARAM_RAW); + $mform->addElement('editor', 'content_editor', get_string('submissioncontent', 'workshop'), null, $contentoptions); + $mform->setType('content', PARAM_RAW); if ($workshop->nattachments > 0) { $mform->addElement('static', 'filemanagerinfo', get_string('nattachments', 'workshop'), $workshop->nattachments); @@ -54,8 +54,8 @@ class workshop_submission_form extends moodleform { null, $attachmentoptions); } - $mform->addElement('hidden', 'id'); - $mform->addElement('hidden', 'cmid'); + $mform->addElement('hidden', 'id', $current->id); + $mform->addElement('hidden', 'cmid', $cm->id); $this->add_action_buttons(); -- 2.39.5