From 5fd75ed8892ef7aa1047f3a709d385ba5df19f1a Mon Sep 17 00:00:00 2001 From: Loc Nguyen Date: Fri, 22 Jul 2016 20:20:42 +0700 Subject: [PATCH] MDL-54945 workshop: Workshop portfolio API integration Users can export their own submission Users can export feedback/assessment received from other users --- mod/workshop/classes/portfolio_caller.php | 571 ++++++++++++++++++ mod/workshop/db/access.php | 18 + mod/workshop/lang/en/workshop.php | 5 + mod/workshop/submission.php | 74 ++- .../tests/behat/behat_mod_workshop.php | 14 + .../tests/behat/export_assessment.feature | 141 +++++ .../tests/behat/export_submission.feature | 120 ++++ mod/workshop/tests/portfolio_caller_test.php | 304 ++++++++++ mod/workshop/version.php | 2 +- 9 files changed, 1246 insertions(+), 3 deletions(-) create mode 100644 mod/workshop/classes/portfolio_caller.php create mode 100644 mod/workshop/tests/behat/export_assessment.feature create mode 100644 mod/workshop/tests/behat/export_submission.feature create mode 100644 mod/workshop/tests/portfolio_caller_test.php diff --git a/mod/workshop/classes/portfolio_caller.php b/mod/workshop/classes/portfolio_caller.php new file mode 100644 index 00000000000..c20ae18f99f --- /dev/null +++ b/mod/workshop/classes/portfolio_caller.php @@ -0,0 +1,571 @@ +. + +/** + * Workshop portfolio caller class to integrate with portfolio API. + * + * @package mod_workshop + * @copyright Loc Nguyen + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); +require_once($CFG->libdir . '/portfolio/caller.php'); + + +/** + * Workshop portfolio caller subclass to handle export submission and assessment to portfolio. + * + * @package mod_workshop + * @copyright Loc Nguyen + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class mod_workshop_portfolio_caller extends portfolio_module_caller_base { + /** + * @var int ID of submission. + */ + protected $submissionid; + /** + * @var int ID of assessment. + */ + protected $assessmentid; + /** + * @var stdClass Course module. + */ + protected $cm; + /** + * @var array Submission files list. + */ + protected $submissionfiles = array(); + /** + * @var array Assessment files list. + */ + protected $assessmentfiles = array(); + + /** + * @var stdClass Submission object load from DB. + */ + private $submission; + /** + * @var stdClass Assessment object. + */ + private $assessment; + /** + * @var stdClass User object. + */ + private $author; + /** + * @var boolean Show author permission. + */ + private $showauthor; + + /** + * Return array of expected call back arguments + * + * and whether they are required or not. + * + * @return array + */ + public static function expected_callbackargs() { + return array( + 'submissionid' => false, + 'assessmentid' => false, + ); + } + + /** + * Load data required for the export. + * + * Load submission and assessment by submissionid, assessmentid. + * + * @return void + */ + public function load_data() { + global $DB; + + $this->submission = $DB->get_record('workshop_submissions', array('id' => $this->submissionid), '*', MUST_EXIST); + $this->cm = get_coursemodule_from_instance('workshop', $this->submission->workshopid, 0, false, MUST_EXIST); + $this->author = $DB->get_record('user', array('id' => $this->submission->authorid)); + + $workshoprecord = $DB->get_record('workshop', array('id' => $this->cm->instance), '*', MUST_EXIST); + $course = $DB->get_record('course', array('id' => $this->cm->course), '*', MUST_EXIST); + $this->workshop = new workshop($workshoprecord, $this->cm, $course); + + // Load data for export assessment. + if ($this->submissionid && $this->assessmentid) { + $assessments = $this->workshop->get_assessments_of_submission($this->submission->id); + $this->assessment = new stdClass(); + $this->assessment = $assessments[$this->assessmentid]; + $fs = get_file_storage(); + $this->assessmentfiles = $fs->get_area_files($this->workshop->context->id, 'mod_workshop', + 'overallfeedback_attachment', $this->assessment->id); + } + // Load data for export submission. + if ($this->submissionid && !$this->assessmentid) { + $fs = get_file_storage(); + $submissioncontentfiles = $fs->get_area_files($this->workshop->context->id, + 'mod_workshop', 'submission_content', $this->submissionid); + $submissionattachmentfiles = $fs->get_area_files($this->workshop->context->id, + 'mod_workshop', 'submission_attachment', $this->submissionid); + $submissioninstructionfiles = $fs->get_area_files($this->workshop->context->id, + 'mod_workshop', 'instructauthors'); + $this->submissionfiles = array_merge($submissioncontentfiles, $submissionattachmentfiles, $submissioninstructionfiles); + + // Check anonymity of exported, show author or not. + $ispublished = ($this->workshop->phase == workshop::PHASE_CLOSED + and $this->submission->published == 1 + and has_capability('mod/workshop:viewpublishedsubmissions', $this->workshop->context)); + $seenaspublished = false; // Is the submission seen as a published submission? + + if ($ispublished) { + $seenaspublished = true; + } + if ($seenaspublished) { + $this->showauthor = has_capability('mod/workshop:viewauthorpublished', $this->workshop->context); + } else { + $this->showauthor = has_capability('mod/workshop:viewauthornames', $this->workshop->context); + } + } + } + + /** + * Prepare the package ready to be passed off to the portfolio plugin. + * + * @return void + */ + public function prepare_package() { + // Set up the leap2a writer if we need it. + $writingleap = false; + if ($this->exporter->get('formatclass') == PORTFOLIO_FORMAT_LEAP2A) { + $leapwriter = $this->exporter->get('format')->leap2a_writer(); + $writingleap = true; + } + + if ($this->submissionid && $this->assessmentid) { + $assessmenthtml = $this->prepare_assessment($this->assessment); + $content = preg_replace('#(.*?)#is', '', $assessmenthtml); + $name = 'assessment.html'; + if ($writingleap) { + $this->prepare_assessment_leap2a($leapwriter, $this->assessment, $content); + $content = $leapwriter->to_xml(); + $name = $this->exporter->get('format')->manifest_name(); + } + } + if ($this->submissionid && !$this->assessmentid) { + $submissionhtml = $this->prepare_submission($this->submission); + $content = $submissionhtml; + $name = 'submission.html'; + if ($writingleap) { + $this->prepare_submission_leap2a($leapwriter, $this->submission, $content); + $content = $leapwriter->to_xml(); + $name = $this->exporter->get('format')->manifest_name(); + } + } + $manifest = ($this->exporter->get('format') instanceof PORTFOLIO_FORMAT_RICH); + $this->get('exporter')->write_new_file($content, $name, $manifest); + } + + /** + * Helper function to output submission for export. + * + * This is cut down version of workshop submission renderer function. + * + * @param object $submission + * @return string + */ + private function prepare_submission($submission) { + global $CFG; + $output = ''; + $output .= ''; + $output .= html_writer::tag("h2", $this->workshop->name); + + // Write submission content. + $output .= html_writer::start_tag('div', array('class' => 'submissionheader', 'style' => 'background-color: #ddd;')); + $output .= html_writer::tag("h3", format_string($submission->title)); + if ($this->showauthor) { + $output .= html_writer::tag('div', get_string('byfullnamewithoutlink', 'workshop', fullname($this->author))); + } + $created = get_string('userdatecreated', 'workshop', userdate($submission->timecreated)); + $output .= html_writer::tag("div", $created, array('style' => 'font-size:x-small')); + + if ($submission->timemodified > $submission->timecreated) { + $modified = get_string('userdatemodified', 'workshop', userdate($submission->timemodified)); + $output .= html_writer::tag("div", $modified, array('style' => 'font-size:x-small')); + } + $output .= html_writer::end_tag('div'); + $format = $this->get('exporter')->get('format'); + $content = portfolio_rewrite_pluginfile_urls($submission->content, $this->workshop->context->id, 'mod_workshop', + 'submission_content', $submission->id, $format); + $content = format_text($content, $submission->contentformat); + $output .= html_writer::tag("div", $content); + if ($this->submissionfiles) { + $outputfiles = ''; + foreach ($this->submissionfiles as $file) { + if ($file->is_directory()) { + continue; + } + + $filename = $file->get_filename(); + $filearea = $file->get_filearea(); + $type = $file->get_mimetype(); + $linkhtml = $format->file_output($file); + + if ($filearea == "submission_attachment") { + $outputfiles .= html_writer::tag('li', $linkhtml, array('class' => $type)); + } + + if ($filename) { + $this->get('exporter')->copy_existing_file($file); + } + + if (!empty($CFG->enableplagiarism)) { + require_once($CFG->libdir . '/plagiarismlib.php'); + $outputfiles .= plagiarism_get_links(array('userid' => $file->get_userid(), + 'file' => $file, + 'cmid' => $this->cm->id, + 'course' => $this->cm->course)); + } + } + $output .= $outputfiles; + } + + // Write submission instruction. + if (trim($this->workshop->instructauthors)) { + $output .= html_writer::tag("h3", get_string('instructauthors', 'workshop')); + $format = $this->get('exporter')->get('format'); + $instructauthorscontent = portfolio_rewrite_pluginfile_urls($this->workshop->instructauthors, + $this->workshop->context->id, 'mod_workshop', 'instructauthors', 0, $format); + $output .= $instructauthorscontent; + } + + return $output; + } + + /** + * Helper function to add a leap2a entry element that corresponds to a submission, + * including any attachments. + * + * The entry/ies are added directly to the leapwriter, which is passed by ref. + * + * @param portfolio_format_leap2a_writer $leapwriter writer object to add entries to + * @param object $submission the stdclass object representing the database record + * @param string $submissionhtml the content of the submission + * + * @return int id of new entry + */ + private function prepare_submission_leap2a(portfolio_format_leap2a_writer $leapwriter, $submission, $submissionhtml) { + global $DB; + $entry = new portfolio_format_leap2a_entry('workshopsubmission' . $submission->id, $submission->title, + 'resource', $submissionhtml); + $entry->published = $submission->timecreated; + $entry->updated = $submission->timemodified; + $entry->author = $DB->get_record('user', array('id' => $submission->authorid), 'id,firstname,lastname,email'); + + if (is_array($this->submissionfiles) && array_key_exists($submission->id, $this->submissionfiles) + && is_array($this->submissionfiles[$submission->id])) { + $leapwriter->link_files($entry, $this->submissionfiles[$submission->id], 'workshopsubmission' + . $submission->id . 'attachment'); + } + $entry->add_category('web', 'resource_type'); + $leapwriter->add_entry($entry); + return $entry->id; + } + + /** + * Helper function to output assessment for export. + * + * This is a cut down function of workshop assessment renderer function. + * + * @param object $assessment the stdclass object representing the database record + * @return string + */ + private function prepare_assessment($assessment) { + global $PAGE; + global $CFG; + global $USER; + $strategy = $this->workshop->grading_strategy_instance(); + $mform = $strategy->get_assessment_form($PAGE->url, 'assessment', $assessment, false); + $userassessment = $this->workshop->get_assessment_of_submission_by_user($assessment->submissionid, $USER->id); + $isreviewer = !empty($userassessment); + if ($isreviewer) { + $showreviewer = true; + } else { + $showreviewer = has_capability('mod/workshop:viewreviewernames', $this->workshop->context); + } + + $fs = get_file_storage(); + $options = array( + 'showreviewer' => $showreviewer, + 'showauthor' => $this->showauthor, + 'showform' => !is_null($assessment->grade), + 'showweight' => true, + ); + $displayassessment = $this->workshop->prepare_assessment($assessment, $mform, $options); + + $output = ''; + $output .= ''; + + // Start write assessment content. + $anonymous = is_null($displayassessment->reviewer); + + $output .= html_writer::start_tag('div', array('class' => 'assessmentheader', 'style' => 'background-color: #ddd;')); + + if (!empty($displayassessment->title)) { + $title = s($displayassessment->title); + } else { + $title = get_string('assessmentbyyourself', 'workshop'); + } + + $output .= html_writer::tag("div", $title); + + if (!$anonymous) { + $reviewer = $displayassessment->reviewer; + $output .= html_writer::tag("div", get_string('byfullnamewithoutlink', 'workshop', fullname($reviewer))); + } + + if (is_null($displayassessment->realgrade)) { + $output .= html_writer::tag("div", get_string('notassessed', 'workshop')); + } else { + $a = new stdClass(); + $a->max = $displayassessment->maxgrade; + $a->received = $displayassessment->realgrade; + $output .= html_writer::tag("div", get_string('gradeinfo', 'workshop', $a)); + + if (!is_null($displayassessment->weight) and $displayassessment->weight != 1) { + $output .= html_writer::tag("div", get_string('weightinfo', 'workshop', $displayassessment->weight)); + } + } + $output .= html_writer::end_tag('div'); + + $dir = $this->get('exporter')->get('format')->get_file_directory(); + + if (!is_null($displayassessment->form)) { + $output .= html_writer::tag("div", get_string('assessmentform', 'workshop')); + $contentform = self::moodleform($displayassessment->form); + $contentform = $this->portfolio_caller_rewrite_pluginfile_urls($contentform, $dir); + $output .= html_writer::tag("div", $contentform); + if (!$displayassessment->form->is_editable()) { + $content = $displayassessment->get_overall_feedback_content(); + $content = $this->portfolio_caller_rewrite_pluginfile_urls($content, $dir); + if ($content != '') { + $output .= html_writer::tag("div", get_string('overallfeedback', 'workshop')); + $output .= html_writer::tag("div", $content); + } + // Export overall feedback files. + $overallfeedbackfiles = $fs->get_area_files($this->workshop->context->id, + 'mod_workshop', 'overallfeedback_content', $assessment->id); + foreach ($overallfeedbackfiles as $file) { + $this->get('exporter')->copy_existing_file($file); + } + } + + // Export description files. + $assessmentdescriptionfiles = $fs->get_area_files($this->workshop->context->id, + 'workshopform_' . $this->workshop->strategy, 'description'); + foreach ($assessmentdescriptionfiles as $file) { + $this->get('exporter')->copy_existing_file($file); + } + } + + if ($this->assessmentfiles) { + $outputfiles = ''; + $format = $this->get('exporter')->get('format'); + foreach ($this->assessmentfiles as $file) { + if ($file->is_directory()) { + continue; + } + $type = $file->get_mimetype(); + $linkhtml = $format->file_output($file); + $outputfiles .= html_writer::tag('li', $linkhtml, array('class' => $type)); + + $this->get('exporter')->copy_existing_file($file); + + if (!empty($CFG->enableplagiarism)) { + require_once($CFG->libdir.'/plagiarismlib.php'); + $outputfiles .= plagiarism_get_links(array('userid' => $file->get_userid(), + 'file' => $file, + 'cmid' => $this->cm->id, + 'course' => $this->cm->course)); + } + } + $output .= $outputfiles; + } + + return $output; + } + + + /** + * Helper function to add a leap2a entry element that corresponds to a assessment, + * including any attachments. + * + * The entry/ies are added directly to the leapwriter, which is passed by ref. + * + * @param portfolio_format_leap2a_writer $leapwriter writer object to add entries to + * @param object $assessment the stdclass object representing the database record + * @param string $assessmenthtml the content of the assessment + * + * @return int id of new entry + */ + private function prepare_assessment_leap2a(portfolio_format_leap2a_writer $leapwriter, $assessment, $assessmenthtml) { + global $DB; + $entry = new portfolio_format_leap2a_entry('workshopassessment' . $assessment->id, + $assessment->title, 'resource', $assessmenthtml); + $entry->published = $assessment->timecreated; + $entry->updated = $assessment->timemodified; + $entry->author = $DB->get_record('user', array('id' => $assessment->reviewerid), 'id,firstname,lastname,email'); + + if (is_array($this->assessmentfiles) && array_key_exists($assessment->id, $this->assessmentfiles) + && is_array($this->assessmentfiles[$assessment->id])) { + $leapwriter->link_files($entry, $this->assessmentfiles[$assessment->id], 'workshopassessment' + . $assessment->id . 'attachment'); + } + $entry->add_category('web', 'resource_type'); + $leapwriter->add_entry($entry); + return $entry->id; + } + + /** + * Return url for redirecting user when cancel or go back. + * + * @return string + */ + public function get_return_url() { + $returnurl = new moodle_url('/mod/workshop/submission.php', + array('cmid' => $this->cm->id)); + return $returnurl->out(); + } + + /** + * Get navigation that logically follows from the place the user was before. + * + * @return array + */ + public function get_navigation() { + $link = new moodle_url('/mod/workshop/submission.php', + array('cmid' => $this->cm->id)); + $navlinks = array(); + $navlinks[] = array( + 'name' => format_string($this->submission->title), + 'link' => $link->out(), + 'type' => 'title' + ); + return array($navlinks, $this->cm); + } + + /** + * How long might we expect this export to take. + * + * @return constant one of PORTFOLIO_TIME_XX + */ + public function expected_time() { + return PORTFOLIO_TIME_LOW; + } + + /** + * Make sure that the current user is allowed to do the export. + * + * @uses CONTEXT_MODULE + * @return boolean + */ + public function check_permissions() { + $context = context_module::instance($this->cm->id); + if ($this->submissionid && $this->assessmentid) { + return has_capability('mod/workshop:exportownsubmission', $context) + && has_capability('mod/workshop:exportownsubmissionassessment', $context); + } + return has_capability('mod/workshop:exportownsubmission', $context); + } + + /** + * Return the sha1 of this content. + * + * @return string + */ + public function get_sha1() { + if ($this->submissionid && $this->assessmentid) { + return sha1($this->assessment->id . ',' . $this->assessment->title . ',' . $this->assessment->timecreated); + } + if ($this->submissionid && !$this->assessmentid) { + return sha1($this->submission->id . ',' . $this->submission->title . ',' . $this->submission->timecreated); + } + } + + /** + * Return a nice name to be displayed about this export location. + * + * @return string + */ + public static function display_name() { + return get_string('modulename', 'workshop'); + } + + /** + * What formats this function *generally* supports. + * + * @return array + */ + public static function base_supported_formats() { + return array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_PLAINHTML, PORTFOLIO_FORMAT_LEAP2A); + } + + /** + * Helper method dealing with the fact we can not just fetch the output of moodleforms. + * + * @param moodleform $mform + * @return string HTML + */ + protected static function moodleform(moodleform $mform) { + ob_start(); + $mform->display(); + $o = ob_get_contents(); + ob_end_clean(); + return $o; + } + + /** + * Helper method dealing with the fact we can not just fetch the output of moodleforms. + * + * @param string $text HTML string to rewrite url + * @param string $dir rewrite file directory + * @return string HTML + */ + public static function portfolio_caller_rewrite_pluginfile_urls($text, $dir) { + $doc = new DOMDocument(); + $doc->loadHTML($text); + + $imagetags = $doc->getElementsByTagName('img'); + foreach ($imagetags as $tag) { + $src = $tag->getAttribute('src'); + if (strpos($src, 'pluginfile.php') !== false) { + $rewriteurl = $dir . basename($src); + $text = str_replace($src, $rewriteurl, $text); + } + } + + $atags = $doc->getElementsByTagName('a'); + foreach ($atags as $atag) { + $href = $atag->getAttribute('href'); + if (strpos($href, 'pluginfile.php') !== false) { + $rewriteurl = $dir . basename($href); + $text = str_replace($href, $rewriteurl, $text); + } + } + + return $text; + } +} + diff --git a/mod/workshop/db/access.php b/mod/workshop/db/access.php index dc7cec424e7..c93e3d41ff2 100644 --- a/mod/workshop/db/access.php +++ b/mod/workshop/db/access.php @@ -244,4 +244,22 @@ $capabilities = array( 'manager' => CAP_ALLOW ) ), + + // Ability to export to portfolio of submission only. + 'mod/workshop:exportownsubmission' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'student' => CAP_ALLOW + ) + ), + + // Ability to export to portfolio of submission's assessment. + 'mod/workshop:exportownsubmissionassessment' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'student' => CAP_ALLOW + ) + ), ); diff --git a/mod/workshop/lang/en/workshop.php b/mod/workshop/lang/en/workshop.php index 996a83ee738..4aa252d5343 100644 --- a/mod/workshop/lang/en/workshop.php +++ b/mod/workshop/lang/en/workshop.php @@ -73,6 +73,7 @@ $string['assignedassessments'] = 'Assigned submissions to assess'; $string['assignedassessmentsnone'] = 'You have no assigned submission to assess'; $string['backtoeditform'] = 'Back to editing form'; $string['byfullname'] = 'by {$a->name}'; +$string['byfullnamewithoutlink'] = 'by {$a}'; $string['calculategradinggrades'] = 'Calculate assessment grades'; $string['calculategradinggradesdetails'] = 'expected: {$a->expected}
calculated: {$a->calculated}'; $string['calculatesubmissiongrades'] = 'Calculate submission grades'; @@ -143,6 +144,8 @@ $string['examplesbeforesubmission'] = 'Examples must be assessed before own subm $string['examplesmode'] = 'Mode of examples assessment'; $string['examplesubmissions'] = 'Example submissions'; $string['examplesvoluntary'] = 'Assessment of example submission is voluntary'; +$string['exportsubmission'] = 'Export submission to portfolio'; +$string['exportsubmissionassessment'] = 'Export assessment to portfolio'; $string['feedbackauthor'] = 'Feedback for the author'; $string['feedbackauthorattachment'] = 'Attachment'; $string['feedbackby'] = 'Feedback by {$a}'; @@ -331,6 +334,8 @@ $string['withoutsubmission'] = 'Reviewer without own submission'; $string['workshop:addinstance'] = 'Add a new workshop'; $string['workshop:allocate'] = 'Allocate submissions for review'; $string['workshop:editdimensions'] = 'Edit assessment forms'; +$string['workshop:exportownsubmission'] = 'Export own submission only'; +$string['workshop:exportownsubmissionassessment'] = 'Export own assessment in submission'; $string['workshop:deletesubmissions'] = 'Delete submissions'; $string['workshop:ignoredeadlines'] = 'Ignore time restrictions'; $string['workshop:manageexamples'] = 'Manage example submissions'; diff --git a/mod/workshop/submission.php b/mod/workshop/submission.php index 5b909868c04..349ed003985 100644 --- a/mod/workshop/submission.php +++ b/mod/workshop/submission.php @@ -1,5 +1,4 @@ context); $canpublish = has_capability('mod/workshop:publishsubmissions', $workshop->context); $canoverride = (($workshop->phase == workshop::PHASE_EVALUATION) and has_capability('mod/workshop:overridegrades', $workshop->context)); $candeleteall = has_capability('mod/workshop:deletesubmissions', $workshop->context); +$canexportownsubmission = !empty($CFG->enableportfolios) + && (has_capability('mod/workshop:exportownsubmission', $workshop->context)) && $ownsubmission && !empty($submission->id); +$canexportownsubmissionassessment = !empty($CFG->enableportfolios) + && (has_capability('mod/workshop:exportownsubmission', $workshop->context)) + && (has_capability('mod/workshop:exportownsubmissionassessment', $workshop->context)) + && $ownsubmission && !empty($submission->id); $userassessment = $workshop->get_assessment_of_submission_by_user($submission->id, $USER->id); $isreviewer = !empty($userassessment); $editable = ($cansubmit and $ownsubmission); @@ -139,6 +144,11 @@ if (!$candeleteall and $ownsubmission and $editable) { } } +// Load portfolio lib if user has capability to export. +if ($canexportownsubmission || $canexportownsubmissionassessment) { + require_once($CFG->libdir.'/portfoliolib.php'); +} + if ($submission->id and $delete and $confirm and $deletable) { require_sesskey(); $workshop->delete_submission($submission); @@ -386,6 +396,23 @@ if (!$delete) { $url = new moodle_url($PAGE->url, array('assess' => 1)); echo $output->single_button($url, get_string('assess', 'workshop'), 'post'); } + + // Add portfolio export button for submission. + if ($canexportownsubmission) { + $button = new portfolio_add_button(); + $button->set_callback_options('mod_workshop_portfolio_caller', array('submissionid' => $submission->id), 'mod_workshop'); + $fs = get_file_storage(); + $files = array_merge($fs->get_area_files($workshop->context->id, 'mod_workshop', 'submission_attachment', $submission->id) + , $fs->get_area_files($workshop->context->id, 'mod_workshop', 'submission_content', $submission->id)); + if ($files) { + $button->set_formats(PORTFOLIO_FORMAT_RICHHTML); + } else { + $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML); + } + echo html_writer::start_tag('div', array('class' => 'singlebutton')); + echo $button->to_html(PORTFOLIO_ADD_FULL_FORM, get_string('exportsubmission', 'workshop')); + echo html_writer::end_tag('div'); + } } if (($workshop->phase == workshop::PHASE_CLOSED) and ($ownsubmission or $canviewall)) { @@ -427,9 +454,31 @@ if ($isreviewer) { echo $output->render(new workshop_feedback_reviewer($userassessment)); } } + + // Add portfolio export button for assessment. + if ($canexportownsubmissionassessment) { + $button = new portfolio_add_button(); + $button->set_callback_options('mod_workshop_portfolio_caller', array('submissionid' => $submission->id, + 'assessmentid' => $assessment->id), 'mod_workshop'); + $fs = get_file_storage(); + $files = array_merge($fs->get_area_files($workshop->context->id, 'mod_workshop' + , 'overallfeedback_attachment', $assessment->id) + , $fs->get_area_files($workshop->context->id, 'workshopform_' . $workshop->strategy, 'description') + , $fs->get_area_files($workshop->context->id, 'mod_workshop', 'overallfeedback', $assessment->id)); + + if ($files) { + $button->set_formats(PORTFOLIO_FORMAT_RICHHTML); + } else { + $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML); + } + echo html_writer::start_tag('div', array('class' => 'singlebutton')); + echo $button->to_html(PORTFOLIO_ADD_FULL_FORM, get_string('exportsubmissionassessment', 'workshop')); + echo html_writer::end_tag('div'); + } } -if (has_capability('mod/workshop:viewallassessments', $workshop->context) or ($ownsubmission and $workshop->assessments_available())) { +if (has_capability('mod/workshop:viewallassessments', $workshop->context) + or ($ownsubmission and $workshop->assessments_available())) { // other assessments $strategy = $workshop->grading_strategy_instance(); $assessments = $workshop->get_assessments_of_submission($submission->id); @@ -461,6 +510,27 @@ if (has_capability('mod/workshop:viewallassessments', $workshop->context) or ($o echo $output->render(new workshop_feedback_reviewer($assessment)); } } + + // Add portfolio export button for assessment. + if ($canexportownsubmissionassessment) { + $button = new portfolio_add_button(); + $button->set_callback_options('mod_workshop_portfolio_caller', array('submissionid' => $submission->id, + 'assessmentid' => $assessment->id), 'mod_workshop'); + $fs = get_file_storage(); + $files = array_merge($fs->get_area_files($workshop->context->id, 'mod_workshop' + , 'overallfeedback_attachment', $assessment->id) + , $fs->get_area_files($workshop->context->id, 'workshopform_' . $workshop->strategy, 'description') + , $fs->get_area_files($workshop->context->id, 'mod_workshop', 'overallfeedback', $assessment->id)); + + if ($files) { + $button->set_formats(PORTFOLIO_FORMAT_RICHHTML); + } else { + $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML); + } + echo html_writer::start_tag('div', array('class' => 'singlebutton')); + echo $button->to_html(PORTFOLIO_ADD_FULL_FORM, get_string('exportsubmissionassessment', 'workshop')); + echo html_writer::end_tag('div'); + } } } diff --git a/mod/workshop/tests/behat/behat_mod_workshop.php b/mod/workshop/tests/behat/behat_mod_workshop.php index ec539b264e2..2d159128c3f 100644 --- a/mod/workshop/tests/behat/behat_mod_workshop.php +++ b/mod/workshop/tests/behat/behat_mod_workshop.php @@ -160,4 +160,18 @@ class behat_mod_workshop extends behat_base { } $this->find('xpath', $xpath); } + + /** + * Configure portfolio plugin, set value for portfolio instance + * + * @When /^I set portfolio instance "(?P(?:[^"]|\\")*)" to "(?P(?:[^"]|\\")*)"$/ + * @param string $portfolioinstance + * @param string $value + */ + public function i_set_portfolio_instance_to($portfolioinstance, $value) { + $xpath = "//table[contains(@class, 'generaltable')]//tr//td[contains(text(), '" + . $portfolioinstance . "')]/following-sibling::td//select"; + $select = $this->find('xpath', $xpath); + $select->selectOption($value); + } } diff --git a/mod/workshop/tests/behat/export_assessment.feature b/mod/workshop/tests/behat/export_assessment.feature new file mode 100644 index 00000000000..487a71cb960 --- /dev/null +++ b/mod/workshop/tests/behat/export_assessment.feature @@ -0,0 +1,141 @@ +@mod @mod_workshop +@javascript + +Feature: Workshop submission's assessment export to portfolio + In order to be able to reuse my assessment content in my submission + As a student + I need to be able to export my own submission's assessment from other people + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | student1 | Sam1 | Student1 | student1@example.com | + | student2 | Sam2 | Student2 | student2@example.com | + | teacher1 | Terry1 | Teacher1 | teacher1@example.com | + And the following "courses" exist: + | fullname | shortname | + | Course1 | c2 | + And the following "course enrolments" exist: + | user | course | role | + | student1 | c2 | student | + | student2 | c2 | student | + | teacher1 | c2 | editingteacher | + And the following "activities" exist: + | activity | name | intro | course | idnumber | + | workshop | TestWorkshop | Test workshop description | c2 | workshop1 | + # Admin enable portfolio plugin + And I log in as "admin" + And I expand "Site administration" node + And I follow "Advanced features" + And I set the following administration settings values: + | Enable portfolios | 1 | + And I expand "Plugins" node + And I expand "Portfolios" node + And I follow "Manage portfolios" + And I set portfolio instance "File download" to "Enabled and visible" + And I click on "Save" "button" + And I log out + # Teacher sets up assessment form and changes the phase to submission. + And I log in as "teacher1" + And I follow "Course1" + And I edit assessment form in workshop "TestWorkshop" as:" + | id_description__idx_0_editor | Aspect1 | + | id_description__idx_1_editor | Aspect2 | + | id_description__idx_2_editor | | + And I change phase in workshop "TestWorkshop" to "Submission phase" + And I log out + # Student1 submits. + And I log in as "student1" + And I follow "Course1" + And I follow "TestWorkshop" + And I add a submission in workshop "TestWorkshop" as:" + | Title | Submission1 | + | Submission content | Some content | + And I log out + # Student2 submits. + And I log in as "student2" + And I follow "Course1" + And I add a submission in workshop "TestWorkshop" as:" + | Title | Submission2 | + | Submission content | Some content | + And I log out + # teacher1 allocates reviewers and changes the phase to assessment + And I log in as "teacher1" + And I follow "Course1" + And I follow "TestWorkshop" + And I allocate submissions in workshop "TestWorkshop" as:" + | Participant | Reviewer | + | Sam1 Student1 | Sam2 Student2 | + | Sam2 Student2 | Sam1 Student1 | + And I follow "TestWorkshop" + And I change phase in workshop "TestWorkshop" to "Assessment phase" + And I log out + # student1 assesses work of student2 + And I log in as "student1" + And I follow "Course1" + And I follow "TestWorkshop" + And I assess submission "Sam2" in workshop "TestWorkshop" as:" + | grade__idx_0 | 5 / 10 | + | peercomment__idx_0 | You can do better | + | grade__idx_1 | 10 / 10 | + | peercomment__idx_1 | Amazing | + | Feedback for the author | Good work | + And I log out + # student2 assesses work of student1 + And I log in as "student2" + And I follow "Course1" + And I follow "TestWorkshop" + And I assess submission "Sam1" in workshop "TestWorkshop" as:" + | grade__idx_0 | 6 / 10 | + | peercomment__idx_0 | | + | grade__idx_1 | 7 / 10 | + | peercomment__idx_1 | | + | Feedback for the author | Keep it up | + And I log out + + Scenario: Hide export to portfolio button of assessment if admin disable portfolio feature + Given I log in as "admin" + And I expand "Site administration" node + And I follow "Advanced features" + And I set the following administration settings values: + | Enable portfolios | 0 | + And I log out + When I log in as "student1" + And I follow "Course1" + And I follow "TestWorkshop" + And I follow "My submission" + Then I should see "Submission1" + Then "Export assessment to portfolio" "button" should not exist + And I log out + + Scenario: Students can export to portfolio their own submission's assessments + Given I log in as "teacher1" + And I follow "Course1" + And I change phase in workshop "TestWorkshop" to "Closed" + And I log out + When I log in as "student1" + And I follow "Course1" + And I follow "TestWorkshop" + And I follow "My submission" + Then I should see "Submission1" + Then "Export assessment to portfolio" "button" should exist + And I click on "Export assessment to portfolio" "button" + Then I should see "Available export formats" + And I click on "Next" "button" + Then I should see "Summary of your export" + And I click on "Continue" "button" + Then I should see "Return to where you were" + And I log out + + Scenario: Students can not export to portfolio the assessment content when viewing submission of other people + Given I log in as "teacher1" + And I follow "Course1" + And I change phase in workshop "TestWorkshop" to "Closed" + And I log out + When I log in as "student2" + And I follow "Course1" + And I follow "TestWorkshop" + And I follow "Submission1" + Then I should see "Assessment" + Then "Export assessment to portfolio" "button" should not exist + And I log out diff --git a/mod/workshop/tests/behat/export_submission.feature b/mod/workshop/tests/behat/export_submission.feature new file mode 100644 index 00000000000..b6352b56ad9 --- /dev/null +++ b/mod/workshop/tests/behat/export_submission.feature @@ -0,0 +1,120 @@ +@mod @mod_workshop +@javascript +Feature: Workshop submission export to portfolio + In order to be able to reuse my submission content + As a student + I need to be able to export my submission + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | student1 | Sam1 | Student1 | student1@example.com | + | student2 | Sam2 | Student2 | student2@example.com | + | teacher1 | Terry1 | Teacher1 | teacher1@example.com | + And the following "courses" exist: + | fullname | shortname | + | Course1 | c1 | + And the following "course enrolments" exist: + | user | course | role | + | student1 | c1 | student | + | student2 | c1 | student | + | teacher1 | c1 | editingteacher | + And the following "activities" exist: + | activity | name | intro | course | idnumber | + | workshop | TestWorkshop | Test workshop description | c1 | workshop1 | + # Admin enable portfolio plugin + And I log in as "admin" + And I expand "Site administration" node + And I follow "Advanced features" + And I set the following administration settings values: + | Enable portfolios | 1 | + And I expand "Plugins" node + And I expand "Portfolios" node + And I follow "Manage portfolios" + And I set portfolio instance "File download" to "Enabled and visible" + And I click on "Save" "button" + And I log out + # Teacher sets up assessment form and changes the phase to submission. + And I log in as "teacher1" + And I follow "Course1" + And I edit assessment form in workshop "TestWorkshop" as:" + | id_description__idx_0_editor | Aspect1 | + | id_description__idx_1_editor | Aspect2 | + | id_description__idx_2_editor | | + And I change phase in workshop "TestWorkshop" to "Submission phase" + And I log out + # Student1 submits. + And I log in as "student1" + And I follow "Course1" + And I follow "TestWorkshop" + And I add a submission in workshop "TestWorkshop" as:" + | Title | Submission1 | + | Submission content | Some content | + And I log out + # Student2 submits. + And I log in as "student2" + And I follow "Course1" + And I add a submission in workshop "TestWorkshop" as:" + | Title | Submission2 | + | Submission content | Some content | + And I log out + # teacher1 allocates reviewers and changes the phase to assessment + And I log in as "teacher1" + And I follow "Course1" + And I follow "TestWorkshop" + And I should see "to allocate: 2" + Then I should see "Workshop submissions report" + And I should see "Submitted (2) / not submitted (0)" + And I should see "Submission1" in the "Sam1 Student1" "table_row" + And I should see "Submission2" in the "Sam2 Student2" "table_row" + And I allocate submissions in workshop "TestWorkshop" as:" + | Participant | Reviewer | + | Sam1 Student1 | Sam2 Student2 | + | Sam2 Student2 | Sam1 Student1 | + And I follow "TestWorkshop" + And I should see "to allocate: 0" + And I change phase in workshop "TestWorkshop" to "Assessment phase" + And I log out + + + Scenario: Hide export to portfolio button if admin disable portfolio feature + Given I log in as "admin" + And I expand "Site administration" node + And I follow "Advanced features" + And I set the following administration settings values: + | Enable portfolios | 0 | + And I log out + When I log in as "student1" + And I follow "Course1" + And I follow "TestWorkshop" + And I follow "My submission" + Then I should see "Submission1" + Then "Export submission to portfolio" "button" should not exist + And I log out + + Scenario: Students can export to portfolio their own submission + Given I log in as "student1" + And I follow "Course1" + And I follow "TestWorkshop" + When I follow "My submission" + Then I should see "Submission1" + Then "Export submission to portfolio" "button" should exist + And I click on "Export submission to portfolio" "button" + Then I should see "Available export formats" + And I click on "Next" "button" + Then I should see "Summary of your export" + And I click on "Continue" "button" + Then I should see "Return to where you were" + And I log out + + Scenario: Students can not export to portfolio when viewing submission of other people + Given I log in as "teacher1" + And I follow "Course1" + And I change phase in workshop "TestWorkshop" to "Closed" + And I log out + When I log in as "student2" + And I follow "Course1" + And I follow "TestWorkshop" + And I follow "Submission1" + Then "Export submission to portfolio" "button" should not exist + And I log out diff --git a/mod/workshop/tests/portfolio_caller_test.php b/mod/workshop/tests/portfolio_caller_test.php new file mode 100644 index 00000000000..cee2d1ff20b --- /dev/null +++ b/mod/workshop/tests/portfolio_caller_test.php @@ -0,0 +1,304 @@ +. + +/** + * Unit tests for mod_workshop_portfolio_caller class defined in mod/workshop/classes/portfolio_caller.php + * + * @package mod_workshop + * @copyright 2016 An Pham Van + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +require_once($CFG->dirroot . '/mod/workshop/locallib.php'); +require_once(__DIR__ . '/fixtures/testable.php'); +require_once($CFG->dirroot . '/mod/workshop/classes/portfolio_caller.php'); + +/** + * Unit tests for mod_workshop_portfolio_caller class + * + * @package mod_workshop + * @copyright 2016 An Pham Van + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class mod_workshop_porfolio_caller_testcase extends advanced_testcase { + + /** @var stdClass $workshop Basic workshop data stored in an object. */ + protected $workshop; + /** @var stdClass mod info */ + protected $cm; + + /** + * Setup testing environment. + */ + protected function setUp() { + parent::setUp(); + $this->setAdminUser(); + $course = $this->getDataGenerator()->create_course(); + $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $course)); + $this->cm = get_coursemodule_from_instance('workshop', $workshop->id, $course->id, false, MUST_EXIST); + $this->workshop = new testable_workshop($workshop, $this->cm, $course); + } + + /** + * Tear down. + */ + protected function tearDown() { + $this->workshop = null; + $this->cm = null; + parent::tearDown(); + } + + /** + * Test function load_data() + * Case 1: User exports the assessment of his/her own submission. + * Assert that this function can load the correct assessment. + */ + public function test_load_data_for_own_submissionassessment() { + $this->resetAfterTest(true); + + $student1 = $this->getDataGenerator()->create_user(); + $student2 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id); + $this->getDataGenerator()->enrol_user($student2->id, $this->workshop->course->id); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id); + $asid1 = $workshopgenerator->create_assessment($subid1, $student2->id); + + $portfoliocaller = new mod_workshop_portfolio_caller(array('submissionid' => $subid1, 'assessmentid' => $asid1)); + $portfoliocaller->load_data(); + + $reflector = new ReflectionObject($portfoliocaller); + $assessment = $reflector->getProperty('assessment'); + $assessment->setAccessible(true); + $result = $assessment->getValue($portfoliocaller); + + $this->assertEquals($asid1, $result->id); + } + + /** + * Test function load_data() + * Case 2: User exports his/her own submission. + * Assert that this function can load the correct submission. + */ + public function test_load_data_for_own_submission() { + $this->resetAfterTest(true); + + $student1 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id); + + $portfoliocaller = new mod_workshop_portfolio_caller(array('submissionid' => $subid1)); + $portfoliocaller->load_data(); + + $reflector = new ReflectionObject($portfoliocaller); + $submission = $reflector->getProperty('submission'); + $submission->setAccessible(true); + + $result = $submission->getValue($portfoliocaller); + + $this->assertEquals($subid1, $result->id); + } + + /** + * Test function get_return_url() + * Assert that this function can return the correct url. + */ + public function test_get_return_url() { + $this->resetAfterTest(true); + + $student1 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id); + + $portfoliocaller = new mod_workshop_portfolio_caller(array('submissionid' => $subid1)); + + $reflector = new ReflectionObject($portfoliocaller); + $cm = $reflector->getProperty('cm'); + $cm->setAccessible(true); + $cm->setValue($portfoliocaller, $this->cm); + + $expected = 'http://www.example.com/moodle/mod/workshop/submission.php?cmid='.$this->cm->id; + $this->assertEquals($expected, $portfoliocaller->get_return_url()); + } + + /** + * Test function get_navigation() + * Assert that this function can return the navigation array. + */ + public function test_get_navigation() { + $this->resetAfterTest(true); + + $student1 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id); + + $portfoliocaller = new mod_workshop_portfolio_caller(array('submissionid' => $subid1)); + $portfoliocaller->load_data(); + + $reflector = new ReflectionObject($portfoliocaller); + $cm = $reflector->getProperty('cm'); + $cm->setAccessible(true); + $cm->setValue($portfoliocaller, $this->cm); + + $this->assertTrue(is_array($portfoliocaller->get_navigation())); + } + + /** + * Test function check_permissions() + * Case 1: User exports assessment. + * Assert that this function can return a boolean value + * to indicate that the user has capability to export the assessment. + */ + public function test_check_permissions_exportownsubmissionassessment() { + global $DB; + $this->resetAfterTest(true); + + $context = context_module::instance($this->cm->id); + $student1 = $this->getDataGenerator()->create_user(); + $student2 = $this->getDataGenerator()->create_user(); + $roleids = $DB->get_records_menu('role', null, '', 'shortname, id'); + $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id, $roleids['student']); + $this->getDataGenerator()->enrol_user($student2->id, $this->workshop->course->id, $roleids['student']); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id); + $asid1 = $workshopgenerator->create_assessment($subid1, $student2->id); + $this->setUser($student1); + + $portfoliocaller = new mod_workshop_portfolio_caller(array('submissionid' => $subid1, 'assessmentid' => $asid1)); + + $reflector = new ReflectionObject($portfoliocaller); + $cm = $reflector->getProperty('cm'); + $cm->setAccessible(true); + $cm->setValue($portfoliocaller, $this->cm); + + // Case 1: If user has capabilities exportownsubmission prevented and exportownsubmissionassessment prevented + // then check_permissions should return false. + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmission', CAP_PREVENT); + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmissionassessment', CAP_PREVENT); + $this->assertFalse($portfoliocaller->check_permissions()); + + // Case 2: If user has capabilities exportownsubmission allowed and exportownsubmissionassessment prevented + // then check_permissions should return false. + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmission', CAP_ALLOW); + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmissionassessment', CAP_PREVENT); + $this->assertFalse($portfoliocaller->check_permissions()); + + // Case 3: If user has capabilities exportownsubmission prevented and exportownsubmissionassessment allowed + // then check_permissions should return false. + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmission', CAP_PREVENT); + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmissionassessment', CAP_ALLOW); + $this->assertFalse($portfoliocaller->check_permissions()); + + // Case 4: If user has capabilities exportownsubmission allowed and exportownsubmissionassessment allowed + // then check_permissions should return true. + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmission', CAP_ALLOW); + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmissionassessment', CAP_ALLOW); + $this->assertTrue($portfoliocaller->check_permissions()); + } + + /** + * Test function check_permissions() + * Case 2: User exports submission. + * Assert that this function can return a boolean value + * to indicate that the user has capability to export submission. + */ + public function test_check_permissions_exportownsubmission() { + global $DB; + $this->resetAfterTest(true); + + $context = context_module::instance($this->cm->id); + $student1 = $this->getDataGenerator()->create_user(); + $roleids = $DB->get_records_menu('role', null, '', 'shortname, id'); + $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id, $roleids['student']); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id); + $this->setUser($student1); + + $portfoliocaller = new mod_workshop_portfolio_caller(array('submissionid' => $subid1)); + $reflector = new ReflectionObject($portfoliocaller); + $cm = $reflector->getProperty('cm'); + $cm->setAccessible(true); + $cm->setValue($portfoliocaller, $this->cm); + + // Case 1: If user has capability to export submission then check_permissions should return true. + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmission', CAP_ALLOW); + $this->assertTrue($portfoliocaller->check_permissions()); + + // Case 2: If user doesn't have capability to export submission then check_permissions should return false. + role_change_permission($roleids['student'], $context, 'mod/workshop:exportownsubmission', CAP_PREVENT); + $this->assertFalse($portfoliocaller->check_permissions()); + } + + /** + * Test function get_sha1() + * Case 1: User exports the assessment of his/her own submission. + * Assert that this function can return a hash string. + */ + public function test_get_sha1_assessment() { + $this->resetAfterTest(true); + + $student1 = $this->getDataGenerator()->create_user(); + $student2 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id); + $this->getDataGenerator()->enrol_user($student2->id, $this->workshop->course->id); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id); + $asid1 = $workshopgenerator->create_assessment($subid1, $student2->id); + + $portfoliocaller = new mod_workshop_portfolio_caller(array('submissionid' => $subid1, 'assessmentid' => $asid1)); + $portfoliocaller->load_data(); + + $this->assertTrue(is_string($portfoliocaller->get_sha1())); + } + + /** + * Test function get_sha1() + * Case 2: User exports his/her own submission. + * Assert that this function can return a hash string. + */ + public function test_get_sha1_submission() { + $this->resetAfterTest(true); + + $student1 = $this->getDataGenerator()->create_user(); + $student2 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($student1->id, $this->workshop->course->id); + $this->getDataGenerator()->enrol_user($student2->id, $this->workshop->course->id); + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $subid1 = $workshopgenerator->create_submission($this->workshop->id, $student1->id); + + $portfoliocaller = new mod_workshop_portfolio_caller(array('submissionid' => $subid1)); + $portfoliocaller->load_data(); + + $this->assertTrue(is_string($portfoliocaller->get_sha1())); + } + + /** + * Test function display_name() + * Assert that this function can return the name of the module ('Workshop'). + */ + public function test_display_name() { + $this->resetAfterTest(true); + $this->assertEquals('Workshop', mod_workshop_portfolio_caller::display_name()); + } + +} diff --git a/mod/workshop/version.php b/mod/workshop/version.php index 63fbfc0f0e8..efe92deea38 100644 --- a/mod/workshop/version.php +++ b/mod/workshop/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2016052300; // The current module version (YYYYMMDDXX) +$plugin->version = 2016062901; // The current module version (YYYYMMDDXX) $plugin->requires = 2016051900; // Requires this Moodle version. $plugin->component = 'mod_workshop'; $plugin->cron = 60; // Give as a chance every minute.