From 7faf78cbae9408fa437b17f9743ef1860654e572 Mon Sep 17 00:00:00 2001 From: Henning Bostelmann Date: Mon, 24 Mar 2014 21:34:42 +0000 Subject: [PATCH] MDL-39929 Assignment: provide file upload area for assignment description --- .../backup/moodle2/backup_assign_stepslib.php | 3 +- .../moodle2/restore_assign_stepslib.php | 1 + mod/assign/lang/en/assign.php | 2 + mod/assign/lib.php | 82 ++++++++++++++++++- mod/assign/locallib.php | 52 +++++++++++- mod/assign/mod_form.php | 13 ++- mod/assign/renderable.php | 6 +- mod/assign/renderer.php | 1 + 8 files changed, 153 insertions(+), 7 deletions(-) diff --git a/mod/assign/backup/moodle2/backup_assign_stepslib.php b/mod/assign/backup/moodle2/backup_assign_stepslib.php index 2ccb03230ef..3e1b2141518 100644 --- a/mod/assign/backup/moodle2/backup_assign_stepslib.php +++ b/mod/assign/backup/moodle2/backup_assign_stepslib.php @@ -148,8 +148,9 @@ class backup_assign_activity_structure_step extends backup_activity_structure_st $assign->annotate_ids('grouping', 'teamsubmissiongroupingid'); // Define file annotations. - // This file area hasn't itemid. + // These file areas don't have an itemid. $assign->annotate_files('mod_assign', 'intro', null); + $assign->annotate_files('mod_assign', 'introattachment', null); // Return the root element (choice), wrapped into standard activity structure. diff --git a/mod/assign/backup/moodle2/restore_assign_stepslib.php b/mod/assign/backup/moodle2/restore_assign_stepslib.php index 40966299065..13abe5ec2d1 100644 --- a/mod/assign/backup/moodle2/restore_assign_stepslib.php +++ b/mod/assign/backup/moodle2/restore_assign_stepslib.php @@ -237,5 +237,6 @@ class restore_assign_activity_structure_step extends restore_activity_structure_ */ protected function after_execute() { $this->add_related_files('mod_assign', 'intro', null); + $this->add_related_files('mod_assign', 'introattachment', null); } } diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php index 4fc211f0adc..c0af1844902 100644 --- a/mod/assign/lang/en/assign.php +++ b/mod/assign/lang/en/assign.php @@ -230,6 +230,8 @@ $string['gradingsummary'] = 'Grading summary'; $string['hideshow'] = 'Hide/Show'; $string['hiddenuser'] = 'Participant '; $string['instructionfiles'] = 'Instruction files'; +$string['introattachments'] = 'Additional files'; +$string['introattachments_help'] = 'Additional files for use in the assignment, such as answer templates, may be added. Download links for the files will then be displayed on the assignment page under the description.'; $string['invalidgradeforscale'] = 'The grade supplied was not valid for the current scale'; $string['invalidfloatforgrade'] = 'The grade provided could not be understood: {$a}'; $string['lastmodifiedsubmission'] = 'Last modified (submission)'; diff --git a/mod/assign/lib.php b/mod/assign/lib.php index 11ce0b690d1..aa029c34578 100644 --- a/mod/assign/lib.php +++ b/mod/assign/lib.php @@ -1039,7 +1039,8 @@ function assign_update_grades($assign, $userid=0, $nullifnone=true) { function assign_get_file_areas($course, $cm, $context) { global $CFG; require_once($CFG->dirroot . '/mod/assign/locallib.php'); - $areas = array(); + + $areas = array(ASSIGN_INTROATTACHMENT_FILEAREA => get_string('introattachments', 'mod_assign')); $assignment = new assign($context, $cm, $course); foreach ($assignment->get_submission_plugins() as $plugin) { @@ -1094,12 +1095,33 @@ function assign_get_file_info($browser, return null; } + $urlbase = $CFG->wwwroot.'/pluginfile.php'; $fs = get_file_storage(); $filepath = is_null($filepath) ? '/' : $filepath; $filename = is_null($filename) ? '.' : $filename; - // Need to find the plugin this belongs to. + // Need to find where this belongs to. $assignment = new assign($context, $cm, $course); + if ($filearea === ASSIGN_INTROATTACHMENT_FILEAREA) { + if (!has_capability('moodle/course:managefiles', $context)) { + // Students can not peak here! + return null; + } + if (!($storedfile = $fs->get_file($assignment->get_context()->id, + 'mod_assign', $filearea, 0, $filepath, $filename))) { + return null; + } + return new file_info_stored($browser, + $assignment->get_context(), + $storedfile, + $urlbase, + $filearea, + $itemid, + true, + true, + false); + } + $pluginowner = null; foreach ($assignment->get_submission_plugins() as $plugin) { if ($plugin->is_visible()) { @@ -1211,3 +1233,59 @@ function assign_get_completion_state($course, $cm, $userid, $type) { return $type; } } + +/** + * Serves intro attachment 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 + * @param array $options additional options affecting the file serving + * @return bool false if file not found, does not return if found - just send the file + */ +function assign_pluginfile($course, + $cm, + context $context, + $filearea, + $args, + $forcedownload, + array $options=array()) { + global $CFG; + + if ($context->contextlevel != CONTEXT_MODULE) { + return false; + } + + require_login($course, false, $cm); + if (!has_capability('mod/assign:view', $context)) { + return false; + } + + require_once($CFG->dirroot . '/mod/assign/locallib.php'); + $assign = new assign($context, $cm, $course); + + if ($filearea !== ASSIGN_INTROATTACHMENT_FILEAREA) { + return false; + } + if (!$assign->show_intro()) { + return false; + } + + $itemid = (int)array_shift($args); + if ($itemid != 0) { + return false; + } + + $relativepath = implode('/', $args); + + $fullpath = "/{$context->id}/mod_assign/$filearea/$itemid/$relativepath"; + + $fs = get_file_storage(); + if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { + return false; + } + send_stored_file($file, 0, 0, $forcedownload, $options); +} diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php index eab9dabda57..c3a4a3807b8 100644 --- a/mod/assign/locallib.php +++ b/mod/assign/locallib.php @@ -56,6 +56,9 @@ define('ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW', 'inreview'); define('ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE', 'readyforrelease'); define('ASSIGN_MARKING_WORKFLOW_STATE_RELEASED', 'released'); +// Name of file area for intro attachments. +define('ASSIGN_INTROATTACHMENT_FILEAREA', 'introattachment'); + require_once($CFG->libdir . '/accesslib.php'); require_once($CFG->libdir . '/formslib.php'); require_once($CFG->dirroot . '/repository/lib.php'); @@ -196,7 +199,7 @@ class assign { * * @return bool showintro */ - protected function show_intro() { + public function show_intro() { if ($this->get_instance()->alwaysshowdescription || time() > $this->get_instance()->allowsubmissionsfromdate) { return true; @@ -604,6 +607,8 @@ class assign { // Cache the course record. $this->course = $DB->get_record('course', array('id'=>$formdata->course), '*', MUST_EXIST); + $this->save_intro_draft_files($formdata); + if ($callplugins) { // Call save_settings hook for submission plugins. foreach ($this->submissionplugins as $plugin) { @@ -955,6 +960,8 @@ class assign { $result = $DB->update_record('assign', $update); $this->instance = $DB->get_record('assign', array('id'=>$update->id), '*', MUST_EXIST); + $this->save_intro_draft_files($formdata); + // Load the assignment so the plugins have access to it. // Call save_settings hook for submission plugins. @@ -982,6 +989,18 @@ class assign { return $result; } + /** + * Save the attachments in the draft areas. + * + * @param stdClass $formdata + */ + protected function save_intro_draft_files($formdata) { + if (isset($formdata->introattachments)) { + file_save_draft_area_files($formdata->introattachments, $this->get_context()->id, + 'mod_assign', ASSIGN_INTROATTACHMENT_FILEAREA, 0); + } + } + /** * Add elements in grading plugin form. * @@ -1233,6 +1252,29 @@ class assign { return $this->course; } + /** + * Count the number of intro attachments. + * + * @return int + */ + protected function count_attachments() { + + $fs = get_file_storage(); + $files = $fs->get_area_files($this->get_context()->id, 'mod_assign', ASSIGN_INTROATTACHMENT_FILEAREA, + 0, 'id', false); + + return count($files); + } + + /** + * Are there any intro attachments to display? + * + * @return boolean + */ + protected function has_visible_attachments() { + return ($this->count_attachments() > 0); + } + /** * Return a grade in user-friendly form, whether it's a scale or not. * @@ -4014,10 +4056,16 @@ class assign { $instance = $this->get_instance(); $o = ''; + + $postfix = ''; + if ($this->has_visible_attachments()) { + $postfix = $this->render_area_files('mod_assign', ASSIGN_INTROATTACHMENT_FILEAREA, 0); + } $o .= $this->get_renderer()->render(new assign_header($instance, $this->get_context(), $this->show_intro(), - $this->get_course_module()->id)); + $this->get_course_module()->id, + '', '', $postfix)); // Display plugin specific headers. $plugins = array_merge($this->get_submission_plugins(), $this->get_feedback_plugins()); diff --git a/mod/assign/mod_form.php b/mod/assign/mod_form.php index 5fd4ccd5bda..835de83f1ef 100644 --- a/mod/assign/mod_form.php +++ b/mod/assign/mod_form.php @@ -42,7 +42,7 @@ class mod_assign_mod_form extends moodleform_mod { * @return void */ public function definition() { - global $CFG, $DB, $PAGE; + global $CFG, $COURSE, $DB, $PAGE; $mform = $this->_form; $mform->addElement('header', 'general', get_string('general', 'form')); @@ -58,6 +58,11 @@ class mod_assign_mod_form extends moodleform_mod { $this->add_intro_editor(true, get_string('description', 'assign')); + $mform->addElement('filemanager', 'introattachments', + get_string('introattachments', 'assign'), + null, array('subdirs' => 0, 'maxbytes' => $COURSE->maxbytes) ); + $mform->addHelpButton('introattachments', 'introattachments', 'assign'); + $ctx = null; if ($this->current && $this->current->coursemodule) { $cm = get_coursemodule_from_instance('assign', $this->current->id, 0, false, MUST_EXIST); @@ -269,6 +274,12 @@ class mod_assign_mod_form extends moodleform_mod { $course = $DB->get_record('course', array('id'=>$this->current->course), '*', MUST_EXIST); $assignment->set_course($course); } + + $draftitemid = file_get_submitted_draft_itemid('introattachments'); + file_prepare_draft_area($draftitemid, $ctx->id, 'mod_assign', ASSIGN_INTROATTACHMENT_FILEAREA, + 0, array('subdirs' => 0)); + $defaultvalues['introattachments'] = $draftitemid; + $assignment->plugin_data_preprocessing($defaultvalues); } diff --git a/mod/assign/renderable.php b/mod/assign/renderable.php index b6b004a4039..3b6e6516610 100644 --- a/mod/assign/renderable.php +++ b/mod/assign/renderable.php @@ -559,6 +559,8 @@ class assign_header implements renderable { public $subpage = ''; /** @var string $preface optional preface (text to show before the heading) */ public $preface = ''; + /** @var string $postfix optional postfix (text to show after the intro) */ + public $postfix = ''; /** * Constructor @@ -575,13 +577,15 @@ class assign_header implements renderable { $showintro, $coursemoduleid, $subpage='', - $preface='') { + $preface='', + $postfix='') { $this->assign = $assign; $this->context = $context; $this->showintro = $showintro; $this->coursemoduleid = $coursemoduleid; $this->subpage = $subpage; $this->preface = $preface; + $this->postfix = $postfix; } } diff --git a/mod/assign/renderer.php b/mod/assign/renderer.php index cdd72ad3cee..5f45d9efd39 100644 --- a/mod/assign/renderer.php +++ b/mod/assign/renderer.php @@ -237,6 +237,7 @@ class mod_assign_renderer extends plugin_renderer_base { if ($header->showintro) { $o .= $this->output->box_start('generalbox boxaligncenter', 'intro'); $o .= format_module_intro('assign', $header->assign, $header->coursemoduleid); + $o .= $header->postfix; $o .= $this->output->box_end(); }