From 81eccf0a36a77069827bdcb7635884451d961796 Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Mon, 4 Jan 2010 18:27:21 +0000 Subject: [PATCH] MDL-20652 workshop: initial work on example submissions --- mod/workshop/example.php | 177 +++++++++++++++++++++++++ mod/workshop/lang/en_utf8/workshop.php | 15 ++- mod/workshop/locallib.php | 65 ++++++++- mod/workshop/renderer.php | 76 ++++++++++- mod/workshop/styles.css | 20 +++ mod/workshop/submission.php | 2 +- mod/workshop/view.php | 38 ++++-- 7 files changed, 373 insertions(+), 20 deletions(-) create mode 100644 mod/workshop/example.php diff --git a/mod/workshop/example.php b/mod/workshop/example.php new file mode 100644 index 0000000000..d4d7d1d274 --- /dev/null +++ b/mod/workshop/example.php @@ -0,0 +1,177 @@ +. + +/** + * View or edit a single example example + * + * @package mod-workshop + * @copyright 2009 David Mudrak + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); +require_once(dirname(__FILE__).'/lib.php'); +require_once(dirname(__FILE__).'/locallib.php'); + +$cmid = required_param('cmid', PARAM_INT); // course module id +$id = required_param('id', PARAM_INT); // example submission id, 0 for the new one +$edit = optional_param('edit', false, PARAM_BOOL); // open for editing? +$delete = optional_param('delete', false, PARAM_BOOL); // example removal requested +$confirm = optional_param('confirm', false, PARAM_BOOL); // example removal request confirmed + +$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); +if (isguestuser()) { + print_error('guestsarenotallowed'); +} + +$workshop = $DB->get_record('workshop', array('id' => $cm->instance), '*', MUST_EXIST); +$workshop = new workshop($workshop, $cm, $course); + +$PAGE->set_url(new moodle_url($workshop->example_url($id), array('edit' => $edit))); + +if ($id) { // example is specified + $example = $workshop->get_example_by_id($id); +} else { // no example specified - create new one + require_capability('mod/workshop:manageexamples', $workshop->context); + $example = new stdClass(); + $example->id = null; + $example->authorid = $USER->id; +} + +$canmanage = has_capability('mod/workshop:manageexamples', $workshop->context); +$isreviewer = $DB->record_exists('workshop_assessments', array('submissionid' => $example->id, 'reviewerid' => $USER->id)); + +if ($id and $delete and $confirm and $canmanage) { + require_sesskey(); + $workshop->delete_submission($example); + redirect($workshop->view_url()); +} + +if ($example->id and ($canmanage or $isreviewer)) { + // ok you can go +} elseif (is_null($example->id) and $canmanage) { + // ok you can go +} else { + print_error('nopermissions'); +} + +if ($edit and $canmanage) { + require_once(dirname(__FILE__).'/submission_form.php'); + + $maxfiles = $workshop->nattachments; + $maxbytes = $workshop->maxbytes; + $contentopts = array('trusttext' => true, 'subdirs' => false, 'maxfiles' => $maxfiles, 'maxbytes' => $maxbytes); + $attachmentopts = array('subdirs' => true, 'maxfiles' => $maxfiles, 'maxbytes' => $maxbytes); + $example = file_prepare_standard_editor($example, 'content', $contentopts, $workshop->context, + 'workshop_submission_content', $example->id); + $example = file_prepare_standard_filemanager($example, 'attachment', $attachmentopts, $workshop->context, + 'workshop_submission_attachment', $example->id); + + $mform = new workshop_submission_form($PAGE->url, array('current' => $example, 'workshop' => $workshop, + 'contentopts' => $contentopts, 'attachmentopts' => $attachmentopts)); + + if ($mform->is_cancelled()) { + redirect($workshop->view_url()); + + } elseif ($canmanage and $formdata = $mform->get_data()) { + $timenow = time(); + if (empty($formdata->id)) { + $formdata->workshopid = $workshop->id; + $formdata->example = 1; + $formdata->authorid = $USER->id; + $formdata->timecreated = $timenow; + $formdata->feedbackauthorformat = FORMAT_HTML; // todo better default + } + $formdata->timemodified = $timenow; + $formdata->title = trim($formdata->title); + $formdata->content = ''; // updated later + $formdata->contentformat = FORMAT_HTML; // updated later + $formdata->contenttrust = 0; // updated later + if (empty($formdata->id)) { + $formdata->id = $DB->insert_record('workshop_submissions', $formdata); + // todo add to log + } + // save and relink embedded images and save attachments + $formdata = file_postupdate_standard_editor($formdata, 'content', $contentopts, $workshop->context, + 'workshop_submission_content', $formdata->id); + $formdata = file_postupdate_standard_filemanager($formdata, 'attachment', $attachmentopts, $workshop->context, + 'workshop_submission_attachment', $formdata->id); + if (empty($formdata->attachment)) { + // explicit cast to zero integer + $formdata->attachment = 0; + } + // store the updated values or re-save the new example (re-saving needed because URLs are now rewritten) + $DB->update_record('workshop_submissions', $formdata); + redirect($workshop->example_url($formdata->id)); + } +} + +$PAGE->set_title($workshop->name); +$PAGE->set_heading($course->fullname); +if ($edit) { + $PAGE->navbar->add(get_string('exampleediting', 'workshop')); +} else { + $PAGE->navbar->add(get_string('example', 'workshop')); +} + +// Output starts here +echo $OUTPUT->header(); +$currenttab = 'submission'; +include(dirname(__FILE__) . '/tabs.php'); +echo $OUTPUT->heading(format_string($workshop->name), 2); + +// if in edit mode, display the form to edit the example +if ($edit and $canmanage) { + $mform->display(); + echo $OUTPUT->footer(); + die(); +} + +// else display the example... +if ($example->id) { + if ($canmanage and $delete) { + echo $OUTPUT->confirm(get_string('exampledeleteconfirm', 'workshop'), + new moodle_url($PAGE->url, array('delete' => 1, 'confirm' => 1)), $workshop->view_url()); + } + $wsoutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE); + echo $wsoutput->example_full($example, true); +} +// ...with an option to edit and remove it +if ($canmanage) { + echo $OUTPUT->container_start('buttonsbar'); + if (empty($edit) and empty($delete)) { + $editbutton = new html_form(); + $editbutton->method = 'get'; + $editbutton->button->text = get_string('exampleedit', 'workshop'); + $editbutton->url = new moodle_url($workshop->example_url($example->id), array('edit' => 'on')); + echo $OUTPUT->button($editbutton); + } + if (empty($delete)) { + $deletebutton = new html_form(); + $deletebutton->method = 'get'; + $deletebutton->button->text = get_string('exampledelete', 'workshop'); + $deletebutton->url = new moodle_url($workshop->example_url($example->id), array('delete' => 'on')); + echo $OUTPUT->button($deletebutton); + } + echo $OUTPUT->container_end(); +} + +// and possibly display the example's review(s) - todo +echo $OUTPUT->footer(); diff --git a/mod/workshop/lang/en_utf8/workshop.php b/mod/workshop/lang/en_utf8/workshop.php index e8d3544d66..40bb067832 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[''] = ''; -$string[''] = ''; -$string[''] = ''; -$string[''] = ''; $string[''] = ''; $string[''] = ''; $string[''] = ''; @@ -41,6 +37,7 @@ $string['allocatedetails'] = 'expected: $a->expected
submitted: $a->submitt $string['allocationdone'] = 'Allocation done'; $string['allocationerror'] = 'Allocation error'; $string['allocation'] = 'Submission allocation'; +$string['allsubmissions'] = 'All submissions'; $string['alreadygraded'] = 'Already graded'; $string['areainstructauthors'] = 'Instructions for submitting'; $string['areasubmissionattachment'] = 'Submission attachments'; @@ -79,9 +76,16 @@ $string['err_removegrademappings'] = 'Unable to remove the unused grade mappings $string['evaluategradeswait'] = 'Please wait until the assessments are evaluated and the grades are calculated'; $string['evaluation'] = 'Grading evaluation'; $string['evaluationmethod'] = 'Grading evaluation method'; +$string['exampleadd'] = 'Add example submission'; +$string['exampledeleteconfirm'] = 'Are you sure you want to delete the following example submission?'; +$string['exampledelete'] = 'Delete example'; +$string['exampleedit'] = 'Edit example'; +$string['exampleediting'] = 'Editing example'; +$string['example'] = 'Example submission'; $string['examplesbeforeassessment'] = 'Examples are available after own submission and must be assessed before assessment phase'; $string['examplesbeforesubmission'] = 'Examples must be assessed before own submission'; $string['examplesmode'] = 'Mode of examples assessment'; +$string['examplesubmissions'] = 'Example submissions'; $string['examplesvoluntary'] = 'Assessment of example submission is voluntary'; $string['feedbackauthor'] = 'Feedback for the author'; $string['feedbackreviewer'] = 'Feedback for the reviewer'; @@ -117,6 +121,7 @@ $string['modulenameplural'] = 'Workshops'; $string['modulename'] = 'Workshop'; $string['mysubmission'] = 'My submission'; $string['nattachments'] = 'Maximum number of submission attachments'; +$string['noexamples'] = 'No examples yet in this workshop'; $string['nogradeyet'] = 'No grade yet'; $string['nosubmissionfound'] = 'No submission found for this user'; $string['nosubmissions'] = 'No submissions yet in this workshop'; @@ -133,6 +138,7 @@ $string['phaseclosed'] = 'Closed'; $string['phaseevaluation'] = 'Grading evaluation phase'; $string['phasesetup'] = 'Setup phase'; $string['phasesubmission'] = 'Submission phase'; +$string['prepareexamples'] = 'Prepare example submissions'; $string['previewassessmentform'] = 'Preview'; $string['reassess'] = 'Re-assess'; $string['receivedgrades'] = 'Received grades'; @@ -182,3 +188,4 @@ $string['withoutsubmission'] = 'Reviewer without own submission'; $string['workshopadministration'] = 'Workshop administration'; $string['workshopfeatures'] = 'Workshop features'; $string['workshopname'] = 'Workshop name'; +$string['yoursubmission'] = 'Your submission'; diff --git a/mod/workshop/locallib.php b/mod/workshop/locallib.php index ea2a313725..e85a04d45b 100644 --- a/mod/workshop/locallib.php +++ b/mod/workshop/locallib.php @@ -394,7 +394,7 @@ class workshop { u.picture AS authorpicture, u.imagealt AS authorimagealt FROM {workshop_submissions} s INNER JOIN {user} u ON (s.authorid = u.id) - WHERE s.workshopid = :workshopid AND s.id = :id'; + WHERE s.example = 0 AND s.workshopid = :workshopid AND s.id = :id'; $params = array('workshopid' => $this->id, 'id' => $id); return $DB->get_record_sql($sql, $params, MUST_EXIST); } @@ -421,6 +421,41 @@ class workshop { return $DB->get_record_sql($sql, $params); } + /** + * Returns example submissions for this workshop + * + * @return array of records or an empty array + */ + public function get_examples() { + global $DB; + return $DB->get_records('workshop_submissions', array('workshopid' => $this->id, 'example' => 1), 'title', 'id,title'); + } + + /** + * Returns full record of the given example submission + * + * @param int $id example submission od + * @return object + */ + public function get_example_by_id($id) { + global $DB; + return $DB->get_record('workshop_submissions', + array('id' => $id, 'workshopid' => $this->id, 'example' => 1), '*', MUST_EXIST); + } + + /** + * Removes the submission and all relevant data + * + * @param stdClass $submission record to delete + * @return void + */ + public function delete_submission(stdClass $submission) { + global $DB; + $assessments = $DB->get_records('workshop_assessments', array('submissionid' => $submission->id), '', 'id'); + $this->delete_assessment(array_keys($assessments)); + $DB->delete_records('workshop_submissions', array('id' => $submission->id)); + } + /** * Returns the list of all assessments in the workshop with some data added * @@ -652,6 +687,15 @@ class workshop { return new moodle_url($CFG->wwwroot . '/mod/workshop/submission.php', array('cmid' => $this->cm->id, 'id' => $id)); } + /** + * @param int $id example submission id + * @return moodle_url of the page to view an example submission + */ + public function example_url($id) { + global $CFG; + return new moodle_url($CFG->wwwroot . '/mod/workshop/example.php', array('cmid' => $this->cm->id, 'id' => $id)); + } + /** * @return moodle_url of the mod_edit form */ @@ -773,6 +817,16 @@ class workshop { } $phase->tasks['editform'] = $task; } + if ($this->useexamples and has_capability('mod/workshop:manageexamples', $this->context, $userid)) { + $task = new stdClass(); + $task->title = get_string('prepareexamples', 'workshop'); + if ($DB->count_records('workshop_submissions', array('example' => 1, 'workshopid' => $this->id)) > 0) { + $task->completed = true; + } elseif ($this->phase > self::PHASE_SETUP) { + $task->completed = false; + } + $phase->tasks['prepareexamples'] = $task; + } if (empty($phase->tasks) and $this->phase == self::PHASE_SETUP) { // if we are in the setup phase and there is no task (typical for students), let us // display some explanation what is going on @@ -787,7 +841,8 @@ class workshop { $phase = new stdClass(); $phase->title = get_string('phasesubmission', 'workshop'); $phase->tasks = array(); - if (has_capability('moodle/course:manageactivities', $this->context, $userid)) { + if (($this->usepeerassessment or $this->useselfassessment) + and has_capability('moodle/course:manageactivities', $this->context, $userid)) { $task = new stdClass(); $task->title = get_string('taskinstructreviewers', 'workshop'); $task->link = $this->updatemod_url(); @@ -811,7 +866,6 @@ class workshop { } $phase->tasks['submit'] = $task; } - $phases[self::PHASE_SUBMISSION] = $phase; if (has_capability('mod/workshop:allocate', $this->context, $userid)) { $task = new stdClass(); $task->title = get_string('allocate', 'workshop'); @@ -849,6 +903,7 @@ class workshop { $phase->tasks['allocateinfo'] = $task; } } + $phases[self::PHASE_SUBMISSION] = $phase; // Prepare tasks for the peer-assessment phase (includes eventual self-assessments) $phase = new stdClass(); @@ -874,7 +929,7 @@ class workshop { } } unset($a); - if ($numofpeers) { + if ($this->usepeerassessment and $numofpeers) { $task = new stdClass(); if ($numofpeerstodo == 0) { $task->completed = true; @@ -889,7 +944,7 @@ class workshop { unset($a); $phase->tasks['assesspeers'] = $task; } - if ($numofself) { + if ($this->useselfassessment and $numofself) { $task = new stdClass(); if ($numofselftodo == 0) { $task->completed = true; diff --git a/mod/workshop/renderer.php b/mod/workshop/renderer.php index f80ea960fd..3b3c3d800f 100644 --- a/mod/workshop/renderer.php +++ b/mod/workshop/renderer.php @@ -153,7 +153,6 @@ class mod_workshop_renderer extends plugin_renderer_base { return $o; } - /** * Displays the submission fulltext * @@ -290,6 +289,81 @@ class mod_workshop_renderer extends plugin_renderer_base { return $this->output->container($outputimgs . $outputfiles, 'attachments'); } + /** + * Display a short summary of the example submission + * + * The passed submission object must define at least: id and title + * + * @param stdClass $example The example submission record + * @return string html to be echoed + */ + public function example_summary(stdClass $example) { + global $CFG; + + $o = ''; // output HTML code + $classes = 'submission-summary example'; + $o .= $this->output->container_start($classes); // main wrapper + $link = new html_link(); + $link->url = new moodle_url($CFG->wwwroot . '/mod/workshop/example.php', + array('cmid' => $this->page->context->instanceid, 'id' => $example->id)); + $link->text = format_string($example->title); + $link->set_classes('title'); + $o .= $this->output->link($link); + + $icon = new moodle_action_icon(); + $icon->image->src = $this->old_icon_url('i/edit'); + $icon->image->alt = get_string('edit'); + $icon->link->url = new moodle_url($CFG->wwwroot . '/mod/workshop/example.php', + array('cmid' => $this->page->context->instanceid, 'id' => $example->id, 'edit' => 'on')); + $o .= $this->output->action_icon($icon); + + $icon = new moodle_action_icon(); + $icon->image->src = $this->old_icon_url('t/delete'); + $icon->image->alt = get_string('delete'); + $icon->link->url = new moodle_url($CFG->wwwroot . '/mod/workshop/example.php', + array('cmid' => $this->page->context->instanceid, 'id' => $example->id, 'delete' => 1)); + $o .= $this->output->action_icon($icon); + + $o .= $this->output->container_end(); // end of the main wrapper + return $o; + } + + /** + * Displays the example submission fulltext + * + * By default, this looks similar to a forum post. + * + * @param stdClass $example The example submission data + * @return string html to be echoed + */ + public function example_full(stdClass $example) { + global $CFG; + + $o = ''; // output HTML code + $classes = 'submission-full example'; + $o .= $this->output->container_start($classes); + $o .= $this->output->container_start('header'); + $o .= $this->output->heading(format_string($example->title), 3, 'title'); + $created = get_string('userdatecreated', 'workshop', userdate($example->timecreated)); + $o .= $this->output->container($created, 'userdate created'); + if ($example->timemodified > $example->timecreated) { + $modified = get_string('userdatemodified', 'workshop', userdate($example->timemodified)); + $o .= $this->output->container($modified, 'userdate modified'); + } + $o .= $this->output->container_end(); // end of header + + $content = format_text($example->content, $example->contentformat); + $content = file_rewrite_pluginfile_urls($content, 'pluginfile.php', $this->page->context->id, + 'workshop_submission_content', $example->id); + $o .= $this->output->container($content, 'content'); + + $o .= $this->submission_attachments($example); + + $o .= $this->output->container_end(); // end of example-full + + return $o; + } + /** * Renders the user plannner tool * diff --git a/mod/workshop/styles.css b/mod/workshop/styles.css index 5a83715983..8ca8db9805 100644 --- a/mod/workshop/styles.css +++ b/mod/workshop/styles.css @@ -100,6 +100,22 @@ margin-right: 5px; } +/** + * Example submission - summary display + */ +.mod-workshop .submission-summary.example .title, +.mod-workshop .submission-summary.example .userdate { + margin: 0px 0px 0px 0px; +} + +/** + * Example submission - full display + */ +.mod-workshop .submission-full.example .header .title, +.mod-workshop .submission-full.example .header .userdate { + margin: 0px 0px 0px 0px; +} + /** * Elements generated by the workshop renderer */ @@ -470,6 +486,10 @@ text-align: center; } +.mod-workshop div.buttonsbar .singlebutton { + display: inline; +} + .mod-workshop div.buttonwithhelp div { display: inline; } diff --git a/mod/workshop/submission.php b/mod/workshop/submission.php index 621195df95..13852a9644 100644 --- a/mod/workshop/submission.php +++ b/mod/workshop/submission.php @@ -90,7 +90,7 @@ if ($edit and $ownsubmission) { $timenow = time(); if (empty($formdata->id)) { $formdata->workshopid = $workshop->id; - $formdata->example = 0; // todo add examples support + $formdata->example = 0; $formdata->authorid = $USER->id; $formdata->timecreated = $timenow; $formdata->feedbackauthorformat = FORMAT_HTML; // todo better default diff --git a/mod/workshop/view.php b/mod/workshop/view.php index d0a787cc35..d35ed28759 100644 --- a/mod/workshop/view.php +++ b/mod/workshop/view.php @@ -83,6 +83,22 @@ case workshop::PHASE_SETUP: if (trim(strip_tags($workshop->intro))) { echo $OUTPUT->box(format_module_intro('workshop', $workshop, $workshop->cm->id), 'generalbox', 'intro'); } + if ($workshop->useexamples and has_capability('mod/workshop:manageexamples', $PAGE->context)) { + echo $OUTPUT->box_start('generalbox examples'); + echo $OUTPUT->heading(get_string('examplesubmissions', 'workshop'), 3); + if (! $examples = $workshop->get_examples()) { + echo $OUTPUT->container(get_string('noexamples', 'workshop'), 'noexamples'); + } + foreach ($examples as $example) { + echo $wsoutput->example_summary($example); + } + $editbutton = new html_form(); + $editbutton->method = 'get'; + $editbutton->button->text = get_string('exampleadd', 'workshop'); + $editbutton->url = new moodle_url($workshop->example_url(0), array('edit' => 'on')); + echo $OUTPUT->button($editbutton); + echo $OUTPUT->box_end(); + } break; case workshop::PHASE_SUBMISSION: if (trim(strip_tags($workshop->instructauthors))) { @@ -91,22 +107,26 @@ case workshop::PHASE_SUBMISSION: echo $OUTPUT->box(format_text($instructions, $workshop->instructauthorsformat), array('generalbox', 'instructions')); } if (has_capability('mod/workshop:submit', $PAGE->context)) { + echo $OUTPUT->box_start('generalbox ownsubmission'); + echo $OUTPUT->heading(get_string('yoursubmission', 'workshop'), 3); if ($submission = $workshop->get_submission_by_author($USER->id)) { - echo $OUTPUT->box_start('generalbox mysubmission'); echo $wsoutput->submission_summary($submission, true); - if ($workshop->submitting_allowed()) { - $editbutton = new html_form(); - $editbutton->method = 'get'; - $editbutton->button->text = get_string('editsubmission', 'workshop'); - $editbutton->url = new moodle_url($workshop->submission_url(), array('edit' => 'on', 'id' => $submission->id)); - echo $OUTPUT->button($editbutton); - } - echo $OUTPUT->box_end(); + } else { + echo $OUTPUT->container(get_string('noyoursubmission', 'workshop')); } + if ($workshop->submitting_allowed()) { + $editbutton = new html_form(); + $editbutton->method = 'get'; + $editbutton->button->text = get_string('editsubmission', 'workshop'); + $editbutton->url = new moodle_url($workshop->submission_url(), array('edit' => 'on')); + echo $OUTPUT->button($editbutton); + } + echo $OUTPUT->box_end(); } if (has_capability('mod/workshop:viewallsubmissions', $PAGE->context)) { $shownames = has_capability('mod/workshop:viewauthornames', $PAGE->context); echo $OUTPUT->box_start('generalbox allsubmissions'); + echo $OUTPUT->heading(get_string('allsubmissions', 'workshop'), 3); if (! $submissions = $workshop->get_submissions('all')) { echo $OUTPUT->container(get_string('nosubmissions', 'workshop'), 'nosubmissions'); } -- 2.39.5