diff --git a/CHANGELOG.md b/CHANGELOG.md index 36dc583..be9c064 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,48 @@ +### Date: 2020-September-23 +### Release: v2020092301 + +#### :zap: What's new + +--- + +#### Support for Moodle Quizzes + +Turnitin will be usable as a part of a Moodle quiz when Moodle releases the feature. When enabled for your account, simply add an essay question as one of the quiz questions. A similarity report will be generated when the student submits the quiz. Track this release on the [Moodle Tracker](https://tracker.moodle.org/browse/MDL-32226). + +#### Privacy API declartion now includes the submission’s contents + +The [Moodle Privacy API](https://docs.moodle.org/dev/Privacy_API) helps plugins report what user data a plugin uses so they cna make informed decisions about their personal information. As a part of the Privacy API declartion, we will now includethe contents of the submission to fully support the Privacy APIs goals. + +Thanks to [thepurpleblob](https://github.com/turnitin/moodle-mod_turnitintooltwo/issues/464) for the catch! + +#### Permission to use the Turnitin Integrity plugin can be limited to individual instructors + +Two new permission settings can now be configured that will allow you to specify certain users who have access to the Turnitin Integrity plugin. This can be used to limit use to certain departments or schools within your organization. + +You are now able to choose if a user is able to Enable Turnitin Integrity for an assignment, and choose if they are able to view any generated similarity reports. + +You can take advantage of this new setting by navigation to Site Administration > Users > Permissions > Check system permissions for the user your wish to give access to. + +#### Support for Korean, Japanese, Chinese (Traditional), and Chinese (Simplified) + +Our interface has been fully localized into four new languages. Check out our help site for full step-by-step guides in these languages too + +#### :wrench: Fixes and enhancements + +--- + +#### EULA screen is now not blank after accepting the Turnitin EULA + +Rather than seeing a blank screen, we’ll now show you a simple message confirming that you have accepted our EULA when navigating to /plagiarism/turnitinsim/eula.php?cmd=displayeula + +#### Turnitin will only show on activity types we support + +Turnitin only supports Moodle assignments, forums, and workshops (and quizzes once released by Moodle!). However, it was possible that the option to enable Turnitin would show on the settings page for activity types we don't support. + +To help clear up any confusion, the option to enable Turnitin will now only show on activity types we support. + +--- + ### Date: 2020-July-21 ### Release: v2020072101 diff --git a/ajax/eula_response.php b/ajax/eula_response.php index f9a0acd..205ff79 100644 --- a/ajax/eula_response.php +++ b/ajax/eula_response.php @@ -72,6 +72,8 @@ $data->id = $submission->id; $data->status = TURNITINSIM_SUBMISSION_STATUS_QUEUED; $data->cm = $context->instanceid; + $data->tiiattempts = 0; + $data->tiiretrytime = 0; $DB->update_record('plagiarism_turnitinsim_sub', $data); } diff --git a/backup/moodle2/restore_plagiarism_turnitinsim_plugin.class.php b/backup/moodle2/restore_plagiarism_turnitinsim_plugin.class.php index b08b52d..4756466 100644 --- a/backup/moodle2/restore_plagiarism_turnitinsim_plugin.class.php +++ b/backup/moodle2/restore_plagiarism_turnitinsim_plugin.class.php @@ -156,7 +156,7 @@ public function after_restore_module() { $params->moduleid = $cm->instance; $params->userid = $data->userid; $params->onlinetext = $onlinetext; - $data->itemid = $moduleobject->get_itemid($cm->instance, $data->userid); + $data->itemid = $moduleobject->get_itemid($params); } $DB->insert_record('plagiarism_turnitinsim_sub', $data); diff --git a/classes/observer.php b/classes/observer.php index b79b3c0..37f8907 100644 --- a/classes/observer.php +++ b/classes/observer.php @@ -45,6 +45,7 @@ class plagiarism_turnitinsim_observer { public static function build_event_data($event, $eventtype, $module = '') { $eventdata = $event->get_data(); $eventdata['eventtype'] = $eventtype; + if ($module != '') { $eventdata['other']['modulename'] = $module; } @@ -99,6 +100,16 @@ public static function workshop_assessable_uploaded( $plugin->submission_handler(self::build_event_data($event, 'assessable_submitted', 'workshop')); } + /** + * Observer function to handle the quiz_submitted event in mod_quiz. + * @param \mod_quiz\event\attempt_submitted $event + */ + public static function quiz_submitted( + \mod_quiz\event\attempt_submitted $event) { + $plugin = new plagiarism_plugin_turnitinsim(); + $plugin->submission_handler(self::build_event_data($event, 'quiz_submitted', 'quiz')); + } + /** * Handle the course_module_updated event. * @param \core\event\course_module_updated $event diff --git a/classes/quiz.class.php b/classes/quiz.class.php new file mode 100644 index 0000000..ec2ce08 --- /dev/null +++ b/classes/quiz.class.php @@ -0,0 +1,164 @@ +. + +/** + * Helper class for plagiarism_turnitinsim component in quizzes. + * + * @package plagiarism_turnitinsim + * @copyright 2020 Turnitin + * @author David Winn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Helper class for plagiarism_turnitinsim component in quizzes. + */ +class plagiarism_turnitinsim_quiz { + + /** + * Get the text from the database for the submission. + * + * @param String $itemid The itemid for this submission. + * @return mixed The text of the submission. + * @throws dml_exception + */ + public function get_onlinetext($itemid) { + global $DB; + + $moodletextsubmission = $DB->get_record('question_attempts', array('id' => $itemid), 'responsesummary'); + + if (isset($moodletextsubmission->responsesummary)) { + return $moodletextsubmission->responsesummary; + } + } + + /** + * Get the item id from the database for this submission. + * + * @param object $params The params to call the DB with. + * @return int The itemid. + * @throws dml_exception + */ + public function get_itemid($params) { + global $DB; + + $item = $DB->get_record_sql('SELECT DISTINCT(q.id) FROM {question_attempt_steps} s + RIGHT JOIN {question_attempts} a + ON s.questionattemptid = a.id + RIGHT JOIN {quiz_attempts} q + ON a.questionusageid = q.uniqueid + WHERE q.quiz = ? + AND s.userid = ? + AND a.responsesummary = ? + AND q.state = ?', + array($params->moduleid, $params->userid, $params->onlinetext, 'finished') + ); + + return ($item) ? $item->id : 0; + } + + /** + * Get the actual author of the submission. + * + * @param int $userid The userid as given by Moodle. + * @param int $relateduserid The relateduserid as given by Moodle. + * @return int The authorid. + */ + public function get_author($userid, $relateduserid) { + return (!empty($relateduserid)) ? $relateduserid : $userid; + } + + /** + * Get the group id that a submission belongs to. - (N/A in quizzes). + * + * @param string $itemid The itemid for the submission. + * @return int The group id. + */ + public function get_groupid($itemid) { + return null; + } + + /** + * Return whether the submission is a draft. Never the case with a quiz submission. + * + * @param string $itemid The itemid for the submission. + * @return bool If the submission is a draft. + */ + public function is_submission_draft($itemid) { + return false; + } + + /** + * Return the due date so we can work out report generation time. Not applicable to quizzes. + * + * @param int $id The forum ID we want the due date for. + * @return int The due date for the assignment. + */ + public function get_due_date($id) { + return 0; + } + + /** + * Determines whether the OR links in other posts should be seen. This is not applicable for quizzes. + * + * @param int $courseid The ID for this course. + * @param int $userid The userid. + * @return bool true if showing other posts links. + */ + public function show_other_posts_links($courseid, $userid) { + return true; + } + + /** + * Create the submission event data needed to queue a submission if Turnitin is enabled after a submission. + * + * @param array $linkarray Data passed by Moodle that belongs to a submission. + * @return array Event data. + * @throws coding_exception + * @throws dml_exception + */ + public function create_submission_event_data($linkarray) { + global $USER; + + $cm = get_coursemodule_from_id('', $linkarray['cmid']); + + $eventdata = array(); + $eventdata['contextinstanceid'] = $linkarray['cmid']; + + $eventdata['eventtype'] = 'quiz_submitted'; + $eventdata['userid'] = $USER->id; + $eventdata['objectid'] = $linkarray['area']; + + if (isset($linkarray['file'])) { + $eventdata['other']['pathnamehashes'] = array($linkarray['file']->get_pathnamehash()); + } else { + $params = new stdClass(); + $params->moduleid = $cm->instance; + + $params->userid = $linkarray['userid']; + $params->onlinetext = $linkarray['content']; + } + if (isset($linkarray['userid'])) { + $eventdata['relateduserid'] = $linkarray['userid']; + } + + $eventdata['other']['modulename'] = $cm->modname; + + return $eventdata; + } +} \ No newline at end of file diff --git a/classes/request.class.php b/classes/request.class.php index eeef2fd..828ceba 100644 --- a/classes/request.class.php +++ b/classes/request.class.php @@ -180,7 +180,16 @@ public function send_request($endpoint, $requestbody, $method, $requesttype = 'g curl_setopt($ch, CURLOPT_PROXYUSERPWD, sprintf('%s:%s', $CFG->proxyuser, $CFG->proxypassword)); } + // Set the default for whether a response was found. + $responsefound = true; + $result = curl_exec($ch); + if ($result === false) { + $responsefound = false; + if ($this->logger) { + $this->logger->error('Curl error: ' . curl_error($ch)); + } + } // Add httpstatus to $result. $httpstatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); @@ -188,9 +197,15 @@ public function send_request($endpoint, $requestbody, $method, $requesttype = 'g if (empty($result)) { $result = new stdClass(); } else { + $originaljson = $result; $result = json_decode($result); + // If Json is not valid set httpstatus 400. if (json_last_error() !== JSON_ERROR_NONE) { + if ($this->logger) { + $this->logger->error('The JSON returned was not valid. Returned JSON: '. $originaljson); + } + $result = new stdClass(); $httpstatus = 400; } @@ -208,7 +223,11 @@ public function send_request($endpoint, $requestbody, $method, $requesttype = 'g curl_close($ch); if ($this->logger) { - $this->logger->info('Response: ', array($result)); + if ($responsefound) { + $this->logger->info('Response: ', array($result)); + } else { + $this->logger->info('Response: There was no response from this request.'); + } } return $result; diff --git a/classes/settings.class.php b/classes/settings.class.php index f74bd0a..93c1f64 100644 --- a/classes/settings.class.php +++ b/classes/settings.class.php @@ -49,12 +49,13 @@ public function __construct(plagiarism_turnitinsim_request $tsrequest = null ) { * Add Turnitin settings to module form. * * @param object $mform The Moodle form object. + * @param boolean $canconfigureplugin If this user has permission to configure the plugin. * @param string $context The context, eg module or course. * @param string $modulename The name of the module. * @return mixed Moodle form with settings. * @throws coding_exception */ - public function add_settings_to_module($mform, $context = 'module', $modulename = '') { + public function add_settings_to_module($mform, $canconfigureplugin = false, $context = 'module', $modulename = '') { global $PAGE; if ($context == 'module') { @@ -146,6 +147,15 @@ public function add_settings_to_module($mform, $context = 'module', $modulename ); $mform->addElement('html', html_writer::tag('div', $link)); + if (!$canconfigureplugin) { + $mform->freeze('turnitinenabled'); + $mform->freeze('excludeoptions'); + $mform->freeze('indexoptions'); + $mform->freeze('reportgenoptions'); + $mform->freeze('accessoptions'); + $mform->freeze('queuedrafts'); + } + return $mform; } diff --git a/classes/submission.class.php b/classes/submission.class.php index e8eadcf..44c54f0 100644 --- a/classes/submission.class.php +++ b/classes/submission.class.php @@ -30,6 +30,7 @@ require_once($CFG->dirroot . '/plagiarism/turnitinsim/classes/assign.class.php'); require_once($CFG->dirroot . '/plagiarism/turnitinsim/classes/forum.class.php'); +require_once($CFG->dirroot . '/plagiarism/turnitinsim/classes/quiz.class.php'); require_once($CFG->dirroot . '/plagiarism/turnitinsim/classes/workshop.class.php'); require_once($CFG->dirroot . '/plagiarism/turnitinsim/classes/logging_request.class.php'); require_once($CFG->dirroot . '/plagiarism/turnitinsim/classes/logging_request_info.class.php'); @@ -129,6 +130,11 @@ class plagiarism_turnitinsim_submission { */ public $tiiretrytime; + /** + * @var string The quiz answer unique key, made up for questionusageid and slot number. + */ + public $quizanswer; + /** * @var object The request object. */ @@ -168,6 +174,7 @@ public function __construct(plagiarism_turnitinsim_request $tsrequest = null, $i $this->seterrormessage($submission->errormessage); $this->settiiattempts($submission->tiiattempts); $this->settiiretrytime($submission->tiiretrytime); + $this->setquizanswer($submission->quizanswer); } } @@ -500,6 +507,8 @@ public function handle_create_submission_response($params) { * Uploads a file to the Turnitin submission. */ public function upload_submission_to_turnitin() { + global $DB, $CFG; + // Create request body with file attached. if ($this->type == "file") { $filedetails = $this->get_file_details(); @@ -523,11 +532,39 @@ public function upload_submission_to_turnitin() { // Create module object. $moduleclass = 'plagiarism_turnitinsim_'.$cm->modname; - $moduleobject = new $moduleclass; - // Add text content to request. - $filename = 'onlinetext_'.$this->id.'_'.$this->cm.'_'.$this->itemid.'.txt'; - $textcontent = html_to_text($moduleobject->get_onlinetext($this->getitemid())); + if ($cm->modname == "quiz") { + require_once($CFG->dirroot . '/mod/quiz/locallib.php'); + + $quizattempt = $DB->get_record('quiz_attempts', array('id' => $this->getitemid())); + if (!$quizattempt) { + // If the quiz attempt doesn't exist, we don't want to break the cron. + mtrace(get_string('taskoutputfailedupload', 'plagiarism_turnitinsim', $this->getturnitinid())); + + $this->setstatus(TURNITINSIM_SUBMISSION_STATUS_ERROR); + $this->seterrormessage(get_string('errorquizattemptnotfound', 'plagiarism_turnitinsim')); + $this->settiiattempts(TURNITINSIM_SUBMISSION_MAX_SEND_ATTEMPTS); + $this->update(); + + return; + } + + // Queue each answer to a question. + $attempt = quiz_attempt::create($this->getitemid()); + foreach ($attempt->get_slots() as $slot) { + $qa = $attempt->get_question_attempt($slot); + if ($this->getidentifier() == sha1($qa->get_response_summary())) { + $textcontent = html_to_text($qa->get_response_summary()); + $filename = 'onlinetext_'.$this->id.'_'.$this->cm.'_'.$this->itemid.'.txt'; + break; + } + } + } else { + $moduleobject = new $moduleclass; + // Add text content to request. + $filename = 'onlinetext_'.$this->id.'_'.$this->cm.'_'.$this->itemid.'.txt'; + $textcontent = html_to_text($moduleobject->get_onlinetext($this->getitemid())); + } // Check that the text exists and is not empty. if (empty($textcontent)) { @@ -861,8 +898,10 @@ public function handle_similarity_response($params) { */ public static function get_submission_details($linkarray) { global $DB; - static $cm; + + $quizanswer = 0; + if (empty($cm)) { $cm = get_coursemodule_from_id('', $linkarray["cmid"]); @@ -873,6 +912,11 @@ public static function get_submission_details($linkarray) { } } + // To uniquely identify the quiz answer. + if (!empty($linkarray["component"]) && $linkarray["component"] == "qtype_essay") { + $quizanswer = $linkarray['area'].'-'.$linkarray['itemid']; + } + if (!empty($linkarray['file'])) { $file = $linkarray['file']; $itemid = $file->get_itemid(); @@ -893,18 +937,17 @@ public static function get_submission_details($linkarray) { } } } else if (!empty($linkarray["content"])) { - $identifier = sha1($linkarray['content']); // If user id is empty this must be a group submission. if (empty($linkarray['userid'])) { return $DB->get_record('plagiarism_turnitinsim_sub', array('identifier' => $identifier, - 'type' => 'content', 'cm' => $linkarray['cmid'])); + 'type' => 'content', 'cm' => $linkarray['cmid'], 'quizanswer' => $quizanswer)); } } - return $DB->get_record('plagiarism_turnitinsim_sub', array('userid' => $linkarray['userid'], - 'cm' => $linkarray['cmid'], 'identifier' => $identifier)); + 'cm' => $linkarray['cmid'], 'identifier' => $identifier, 'quizanswer' => $quizanswer)); + } /** @@ -1386,6 +1429,24 @@ public function settiiretrytime($tiiretrytime) { $this->tiiretrytime = $tiiretrytime; } + /** + * Get the key for the quiz answer. + * + * @return string + */ + public function getquizanswer() { + return $this->quizanswer; + } + + /** + * Set the key for the quiz answer. + * + * @param string $quizanswer The key for the quiz answer, made up of questionusageid and slot. + */ + public function setquizanswer($quizanswer) { + $this->quizanswer = $quizanswer; + } + /** * Reset retries. */ diff --git a/db/events.php b/db/events.php index 08ef3d3..76fa369 100644 --- a/db/events.php +++ b/db/events.php @@ -46,6 +46,10 @@ 'eventname' => '\mod_forum\event\assessable_uploaded', 'callback' => 'plagiarism_turnitinsim_observer::forum_assessable_uploaded' ), + array( + 'eventname' => '\mod_quiz\event\attempt_submitted', + 'callback' => 'plagiarism_turnitinsim_observer::quiz_submitted' + ), array( 'eventname' => '\core\event\course_module_updated', 'callback' => 'plagiarism_turnitinsim_observer::module_updated' diff --git a/db/install.xml b/db/install.xml index 9e7bcad..0f4ab20 100644 --- a/db/install.xml +++ b/db/install.xml @@ -22,7 +22,8 @@ - + + diff --git a/db/upgrade.php b/db/upgrade.php index 6845846..fe4bc10 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -290,5 +290,19 @@ function xmldb_plagiarism_turnitinsim_upgrade($oldversion) { upgrade_plugin_savepoint(true, 2020061202, 'plagiarism', 'turnitinsim'); } + if ($oldversion < 2020092301) { + (new handle_deprecation)->unset_turnitinsim_use(); + + $table = new xmldb_table('plagiarism_turnitinsim_sub'); + $field = new xmldb_field('quizanswer', XMLDB_TYPE_CHAR, '32', null, false, null, null, 'tiiretrytime'); + + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + $DB->set_field('plagiarism_turnitinsim_sub', 'quizanswer', 0); + } + + upgrade_plugin_savepoint(true, 2020092301, 'plagiarism', 'turnitinsim'); + } + return true; } \ No newline at end of file diff --git a/lang/en/plagiarism_turnitinsim.php b/lang/en/plagiarism_turnitinsim.php index 8de96b0..f03714e 100644 --- a/lang/en/plagiarism_turnitinsim.php +++ b/lang/en/plagiarism_turnitinsim.php @@ -34,8 +34,10 @@ $string['errortoolarge'] = 'This file will not be submitted to Turnitin as it exceeds the maximum size of {$a} allowed'; $string['eulaaccept'] = 'I accept the Turnitin EULA'; $string['eulaaccepted'] = 'Thank you for accepting the new Turnitin EULA. All future submissions will now be sent to Turnitin for processing.'; +$string['eulaalreadyaccepted'] = 'You have already accepted the latest Turnitin EULA.'; $string['euladecline'] = 'I decline the Turnitin EULA'; $string['euladeclined'] = 'Your submissions will not be sent to Turnitin as you have not accepted the Turnitin End User Licence Agreement.'; +$string['eulanotrequired'] = 'You are not required to accept the Turnitin EULA.'; $string['eulaheader'] = 'Turnitin End User Licence Agreement'; $string['eulalink'] = 'For this submission to be sent to Turnitin, you must accept the Turnitin End User Licence Agreement.'; $string['eulalinkgeneric'] = 'If you would like any of your future submissions to be sent to Turnitin, you must accept the Turnitin End User Licence Agreement.'; @@ -196,4 +198,5 @@ $string['errorenabledfeatures'] = 'Could not get the list of enabled features.'; $string['errorgettingsubmissioninfo'] = 'There was an error attempting to get the submission info.'; $string['errorprocessingdeletedsubmission'] = 'This submission belongs to a deleted assignment and cannot be processed.'; +$string['errorquizattemptnotfound'] = 'The quiz attempt for this submission could not be found.'; $string['help_link'] = 'https://help.turnitin.com/integrity/administrator/moodle.htm#step-four'; diff --git a/lib.php b/lib.php index 60ee186..746ebb6 100644 --- a/lib.php +++ b/lib.php @@ -60,6 +60,9 @@ class plagiarism_plugin_turnitinsim extends plagiarism_plugin { public function get_form_elements_module($mform, $context, $modulename = "") { // This is a bit of a hack and untidy way to ensure the form elements aren't displayed twice. // TODO: Remove once this method is removed. + + $canconfigureplugin = false; + static $hassettings; if ($hassettings) { return; @@ -73,13 +76,28 @@ public function get_form_elements_module($mform, $context, $modulename = "") { $moduletiienabled = empty($modulename) ? "0" : get_config('plagiarism_turnitinsim', 'turnitinmodenabled'.substr($modulename, 4)); - // Exit if Turnitin is not being used for this activity type and location is not default. - if ($location === 'module' && $moduletiienabled === "0") { - return; + if ($location === 'module') { + // Exit if Turnitin is not being used for this activity type and location is not default. + if (empty($moduletiienabled)) { + return; + } + + // Course ID is only passed in on new module - if updating then get it from module id. + $courseid = optional_param('course', 0, PARAM_INT); + if (empty($courseid)) { + $courseid = get_coursemodule_from_id('', $cmid)->course; + } + + // Exit if this user does not have permissions to configure the plugin. + if (has_capability('plagiarism/turnitinsim:enable', context_course::instance($courseid))) { + $canconfigureplugin = true; + } + } else { + $canconfigureplugin = true; } $form = new plagiarism_turnitinsim_settings(); - $form->add_settings_to_module($mform, $location, $modulename); + $form->add_settings_to_module($mform, $canconfigureplugin, $location, $modulename); if ($modsettings = $this->get_settings( $cmid )) { @@ -143,7 +161,7 @@ public function save_form_elements($data) { * @throws moodle_exception */ public function get_links($linkarray) { - global $OUTPUT, $PAGE; + global $DB, $OUTPUT, $PAGE; // Require the relevant JS modules. Only include once. static $jsloaded; @@ -157,6 +175,18 @@ public function get_links($linkarray) { } $output = ''; + // If this is a quiz, retrieve the cmid. + $component = (!empty($linkarray['component'])) ? $linkarray['component'] : ""; + if ($component == "qtype_essay" && !empty($linkarray['area'])) { + $questions = question_engine::load_questions_usage_by_activity($linkarray['area']); + + // Try to get cm using the questions owning context. + $context = $questions->get_owning_context(); + if (empty($linkarray['cmid']) && $context->contextlevel == CONTEXT_MODULE) { + $linkarray['cmid'] = $context->instanceid; + } + } + // Get course module details. static $cm; if (empty($cm) && !empty($linkarray["cmid"])) { @@ -184,16 +214,20 @@ public function get_links($linkarray) { context_module::instance($cm->id) ); - // If the user is a student and they are not allowed to view reports then return empty output. - $plagiarismsettings = $this->get_settings($cm->id); - if (!$instructor && empty($plagiarismsettings->accessstudents)) { - return $output; + // Get the user ID for a quiz submission as it does not exist in the linkarray. + if (!empty($linkarray['file']) && $cm->modname == "quiz") { + $linkarray['userid'] = $DB->get_record( + 'files', + ['id' => $linkarray['file']->get_id()], + 'userid' + )->userid; } // Display cv link and OR score or status. if ((!empty($linkarray['file'])) || (!empty($linkarray['content']))) { $submissionid = ''; $showresubmitlink = false; + $submission = null; // Get turnitin submission details. $plagiarismfile = plagiarism_turnitinsim_submission::get_submission_details($linkarray); @@ -204,10 +238,20 @@ public function get_links($linkarray) { return $output; } - // Render the OR score or current submission status. if ($plagiarismfile) { $submission = new plagiarism_turnitinsim_submission(new plagiarism_turnitinsim_request(), $plagiarismfile->id); + } + // If the user is a student and they are not allowed to view reports, + // and they have accepted the EULA then return empty output. + $plagiarismsettings = $this->get_settings($cm->id); + if (!$instructor && empty($plagiarismsettings->accessstudents) && + $submission->getstatus() !== TURNITINSIM_SUBMISSION_STATUS_EULA_NOT_ACCEPTED) { + return $output; + } + + // Render the OR score or current submission status. + if ($submission) { switch ($submission->getstatus()) { case TURNITINSIM_SUBMISSION_STATUS_QUEUED: $status = html_writer::tag('span', get_string('submissiondisplaystatus:queued', @@ -302,6 +346,7 @@ public function get_links($linkarray) { // If the plugin was enabled after a submission was made then it will not have been sent to Turnitin. Queue it. $moduleclass = 'plagiarism_turnitinsim_'.$cm->modname; $moduleobject = new $moduleclass; + $eventdata = $moduleobject->create_submission_event_data($linkarray); $this->submission_handler($eventdata); @@ -416,8 +461,21 @@ public function print_disclosure($cmid) { // We don't need to continue if the user has accepted the latest EULA and/or EULA acceptance is not required. $user = new plagiarism_turnitinsim_user($USER->id); $features = json_decode(get_config('plagiarism_turnitinsim', 'turnitin_features_enabled')); - if ($user->get_lasteulaaccepted() == $eulaversion || !(bool)$features->tenant->require_eula) { - return ''; + + if ($user->get_lasteulaaccepted() == $eulaversion) { + return html_writer::tag( + 'div', + get_string('eulaalreadyaccepted', 'plagiarism_turnitinsim'), + array('class' => 'eulacontainer', 'id' => 'eulacontainer') + ); + } + + if (!(bool)$features->tenant->require_eula) { + return html_writer::tag( + 'div', + get_string('eulanotrequired', 'plagiarism_turnitinsim'), + array('class' => 'eulacontainer', 'id' => 'eulacontainer') + ); } // Require the JS module to handle the user's eula response. @@ -532,7 +590,6 @@ public function submission_handler($eventdata) { $groupid = $moduleobject->get_groupid($eventdata['objectid']); $submitter = new plagiarism_turnitinsim_user($eventdata['userid']); - // Get the item ID. $itemid = (!empty($eventdata['objectid'])) ? $eventdata['objectid'] : null; // If this is a user confirming a final submission then revert the submission to @@ -568,7 +625,84 @@ public function submission_handler($eventdata) { return true; } + // Quizzes don't pass the content in their event and work differently. + if (($eventdata['eventtype'] == 'quiz_submitted') || + (isset($eventdata['other']['modulename']) && $eventdata['other']['modulename'] == 'quiz')) { + $this->quiz_handler($cm, $eventdata, $sendtoturnitin, $features); + + return true; + } + // Queue files to submit to Turnitin. + $this->queue_files($cm, $eventdata, $sendtoturnitin, $features); + + // Queue text content to submit to Turnitin. + if (!empty($eventdata['other']['content'])) { + $tssubmission = new plagiarism_turnitinsim_submission(new plagiarism_turnitinsim_request()); + $tssubmission->setcm($cm->id); + $tssubmission->setuserid($author); + $tssubmission->setgroupid($groupid); + $tssubmission->setsubmitter($submitter->userid); + $tssubmission->setitemid($itemid); + $tssubmission->setquizanswer(0); + + $identifier = sha1($eventdata['other']['content']); + + $tssubmission->setidentifier($identifier); + $tssubmission->settype(TURNITINSIM_SUBMISSION_TYPE_CONTENT); + + // Check if user has submitted text content for this item previously. + $submission = $DB->get_record_select('plagiarism_turnitinsim_sub', + 'cm = ? AND userid = ? AND itemid = ? AND type = ?', + array($cm->id, $author, $itemid, TURNITINSIM_SUBMISSION_TYPE_CONTENT)); + + // Resubmit text content if this submission is being edited. + if (!empty($submission)) { + $tssubmission->setid($submission->id); + } + + // If the submitter has not accepted the EULA then flag accordingly. + if ($submitter->get_lasteulaaccepted() < get_config('plagiarism_turnitinsim', 'turnitin_eula_version')) { + $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_EULA_NOT_ACCEPTED); + $tssubmission->update(); + return true; + } + + $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_QUEUED); + $tssubmission->calculate_generation_time(); + $tssubmission->settiiattempts(0); + $tssubmission->settiiretrytime(0); + $tssubmission->update(); + } + + return true; + } + + /** + * Method for queuing a file submission. + * + * @param object $cm Information relating to a course module. + * @param array $eventdata - provided by Moodle, should contain enough data to process a submission. + * @param boolean $sendtoturnitin Send if draft submissions are not enabled. + * @param object $features The features available for this account. + * @param string $quizanswer The quiz answer unique key, made up for questionusageid and slot number. + * @throws coding_exception + * @throws dml_exception + */ + public function queue_files($cm, $eventdata, $sendtoturnitin, $features, $quizanswer = '0') { + global $DB; + + // Create module object. + $moduleclass = 'plagiarism_turnitinsim_'.$cm->modname; + $moduleobject = new $moduleclass; + + // Set the author, submitter and group (if applicable). + $author = $moduleobject->get_author($eventdata['userid'], $eventdata['relateduserid'], $cm, $eventdata['objectid']); + $groupid = $moduleobject->get_groupid($eventdata['objectid']); + $submitter = new plagiarism_turnitinsim_user($eventdata['userid']); + + $itemid = (!empty($eventdata['objectid'])) ? $eventdata['objectid'] : null; + if (!empty($eventdata['other']['pathnamehashes'])) { foreach ($eventdata['other']['pathnamehashes'] as $pathnamehash) { $tssubmission = new plagiarism_turnitinsim_submission(new plagiarism_turnitinsim_request()); @@ -579,6 +713,7 @@ public function submission_handler($eventdata) { $tssubmission->setitemid($itemid); $tssubmission->setidentifier($pathnamehash); $tssubmission->settype(TURNITINSIM_SUBMISSION_TYPE_FILE); + $tssubmission->setquizanswer($quizanswer); // Check if this file has been submitted previously and re-use record. $query = ' cm = ? AND userid = ? AND identifier = ? '; @@ -627,7 +762,7 @@ public function submission_handler($eventdata) { // If the submitter has not accepted the EULA then flag accordingly. if ((empty($submitter->get_lasteulaaccepted()) || - $submitter->get_lasteulaaccepted() < get_config('plagiarism_turnitinsim', 'turnitin_eula_version')) && + $submitter->get_lasteulaaccepted() < get_config('plagiarism_turnitinsim', 'turnitin_eula_version')) && (bool)$features->tenant->require_eula ) { $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_EULA_NOT_ACCEPTED); @@ -645,36 +780,66 @@ public function submission_handler($eventdata) { $tssubmission->update(); } } + } + + /** + * Specific method for handling the quiz_submitted event type. + * This is because a quiz might have many questions to queue. + * + * @param object $cm Information relating to a course module. + * @param array $eventdata - provided by Moodle, should contain enough data to process a submission. + * @param boolean $sendtoturnitin Send if draft submissions are not enabled. + * @param object $features The features available for this account. + * @throws coding_exception + * @throws dml_exception + */ + public function quiz_handler($cm, $eventdata, $sendtoturnitin, $features) { + // Create module object. + $moduleclass = 'plagiarism_turnitinsim_'.$cm->modname; + $moduleobject = new $moduleclass; + + // Set the author, submitter and group (if applicable). + $author = $moduleobject->get_author($eventdata['userid'], $eventdata['relateduserid'], $cm, $eventdata['objectid']); + $groupid = $moduleobject->get_groupid($eventdata['objectid']); + $submitter = new plagiarism_turnitinsim_user($eventdata['userid']); + + // Queue every question submitted in a quiz attempt. + $attempt = quiz_attempt::create($eventdata['objectid']); + $context = context_module::instance($attempt->get_cmid()); + foreach ($attempt->get_slots() as $slot) { + $eventdata['other']['pathnamehashes'] = array(); + $qa = $attempt->get_question_attempt($slot); + $quizanswer = $qa->get_usage_id().'-'.$qa->get_slot(); + + $files = $qa->get_last_qt_files('attachments', $context->id); + if ($files) { + foreach ($files as $fileinfo) { + $eventdata['other']['pathnamehashes'][] = $fileinfo->get_pathnamehash(); + } + } + + $this->queue_files($cm, $eventdata, $sendtoturnitin, $features, $quizanswer); + + // Don't queue empty content as it may be a file only question. + if (empty($qa->get_response_summary())) { + continue; + } - // Queue text content to submit to Turnitin. - if (!empty($eventdata['other']['content'])) { $tssubmission = new plagiarism_turnitinsim_submission(new plagiarism_turnitinsim_request()); $tssubmission->setcm($cm->id); $tssubmission->setuserid($author); $tssubmission->setgroupid($groupid); $tssubmission->setsubmitter($submitter->userid); - $tssubmission->setitemid($itemid); - - $identifier = sha1($eventdata['other']['content']); - - $tssubmission->setidentifier($identifier); + $tssubmission->setitemid($eventdata['objectid']); + $tssubmission->setidentifier(sha1($qa->get_response_summary())); $tssubmission->settype(TURNITINSIM_SUBMISSION_TYPE_CONTENT); - - // Check if user has submitted text content for this item previously. - $submission = $DB->get_record_select('plagiarism_turnitinsim_sub', - 'cm = ? AND userid = ? AND itemid = ? AND type = ?', - array($cm->id, $author, $itemid, TURNITINSIM_SUBMISSION_TYPE_CONTENT)); - - // Resubmit text content if this submission is being edited. - if (!empty($submission)) { - $tssubmission->setid($submission->id); - } + $tssubmission->setquizanswer($quizanswer); // If the submitter has not accepted the EULA then flag accordingly. if ($submitter->get_lasteulaaccepted() < get_config('plagiarism_turnitinsim', 'turnitin_eula_version')) { $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_EULA_NOT_ACCEPTED); $tssubmission->update(); - return true; + continue; } $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_QUEUED); @@ -683,7 +848,6 @@ public function submission_handler($eventdata) { $tssubmission->settiiretrytime(0); $tssubmission->update(); } - return true; } /** diff --git a/tests/classes/quiz_test.php b/tests/classes/quiz_test.php new file mode 100644 index 0000000..08472d7 --- /dev/null +++ b/tests/classes/quiz_test.php @@ -0,0 +1,370 @@ +. + +/** + * Tests for quiz module class for plagiarism_turnitinsim component + * + * @package plagiarism_turnitinsim + * @copyright 2020 Turnitin + * @author David Winn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/plagiarism/turnitinsim/classes/quiz.class.php'); +require_once($CFG->dirroot . '/plagiarism/turnitinsim/tests/utilities.php'); +require_once($CFG->dirroot . '/mod/workshop/locallib.php'); +require_once($CFG->dirroot . '/mod/workshop/tests/fixtures/testable.php'); + +/** + * Tests for quiz module class for plagiarism_turnitinsim component + */ +class quiz_test extends advanced_testcase { + + /** + * Sample text used for unit testing a quiz. + */ + const QUIZ_ANSWER_TEXT = 'Generic quiz answer.'; + + /** + * Default module ID used when testing a quiz. + */ + const MODULE_ID = 1; + + /** + * Set config for use in the tests. + */ + public function setup() { + // Set plugin as enabled in config for this module type. + set_config('turnitinapiurl', 'http://www.example.com', 'plagiarism_turnitinsim'); + set_config('turnitinapikey', 1234, 'plagiarism_turnitinsim'); + set_config('turnitinenablelogging', 0, 'plagiarism_turnitinsim'); + + // Set the features enabled. + $featuresenabled = file_get_contents(__DIR__ . '/../fixtures/get_features_enabled_success.json'); + set_config('turnitin_features_enabled', $featuresenabled, 'plagiarism_turnitinsim'); + + $this->student1 = $this->getDataGenerator()->create_user(); + $this->student2 = $this->getDataGenerator()->create_user(); + } + + /** + * Test that get_onlinetext returns the correct text. + * @throws coding_exception + * @throws dml_exception + */ + public function test_get_onlinetext_returns_correct_text() { + global $DB; + + $this->resetAfterTest(); + + // Create a question attempt. + $qattempt = $this->create_question_attempt(); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + $result = $tsquiz->get_onlinetext($qattempt->id); + + $this->assertEquals($result, self::QUIZ_ANSWER_TEXT); + + } + + /** + * Test that online text returns false if no text is found. + */ + public function test_get_onlinetext_returns_false_if_no_text() { + $this->resetAfterTest(); + + $tsassign = new plagiarism_turnitinsim_quiz(); + $result = $tsassign->get_onlinetext(2); + + $this->assertNull($result); + } + + /** + * Test that we get back the correct itemid when get_itemid is called. + */ + public function test_get_itemid_returns_correct_itemid() { + global $DB; + + $this->resetAfterTest(); + + // Create a question attempt, step and quiz attempt. + $questionattempt = $this->create_question_attempt(); + $this->create_question_attempt_step($questionattempt->id); + $quizattempt = $this->create_quiz_attempt($questionattempt->questionusageid); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + + // Create params to call get_item with. + $params = new stdClass(); + $params->moduleid = self::MODULE_ID; + $params->userid = $this->student1->id; + $params->onlinetext = self::QUIZ_ANSWER_TEXT; + + $result = $tsquiz->get_itemid($params); + $this->assertEquals($result, $quizattempt->id); + } + + /** + * Test that we get back 0 if there is no answer. + */ + public function test_get_itemid_returns_zero_if_no_submission() { + global $DB; + + $this->resetAfterTest(); + + // Create a question attempt, step and quiz attempt. + $questionattempt = $this->create_question_attempt(); + $this->create_question_attempt_step($questionattempt->id); + $this->create_quiz_attempt($questionattempt->questionusageid); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + + // Create params to call get_item with. + $params = new stdClass(); + $params->moduleid = self::MODULE_ID; + $params->userid = $this->student1->id; + $params->onlinetext = null; + + $result = $tsquiz->get_itemid($params); + $this->assertEquals($result, 0); + } + + /** + * Test that getting the author returns the related user id. + */ + public function test_get_author_returns_related_user_id() { + $this->resetAfterTest(true); + + // Test that get author returns user2 as the author. + $tsquiz = new plagiarism_turnitinsim_quiz(); + $response = $tsquiz->get_author($this->student1->id, $this->student2->id); + $this->assertEquals($this->student2->id, $response); + + // Test that get author returns user1 as the author because relateduserid is empty. + $tsquiz = new plagiarism_turnitinsim_quiz(); + $response = $tsquiz->get_author($this->student1->id, null); + $this->assertEquals($this->student1->id, $response); + } + + /** + * Test that get_groupid returns expected value. + */ + public function test_get_groupid() { + $this->resetAfterTest(); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + $response = $tsquiz->get_groupid(1); + $this->assertEquals(null, $response); + } + + /** + * Test that is submission draft returns expected value. + */ + public function test_is_submission_draft() { + $this->resetAfterTest(); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + $response = $tsquiz->is_submission_draft(0); + $this->assertEquals(false, $response); + } + + /** + * Test that get due date returns expected value. + */ + public function test_get_due_date() { + $this->resetAfterTest(); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + $response = $tsquiz->get_due_date(0); + $this->assertEquals(0, $response); + } + + /** + * Test that show other posts links returns expected value. + */ + public function test_show_other_posts_links() { + $this->resetAfterTest(); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + $response = $tsquiz->show_other_posts_links(0, 0); + $this->assertEquals(true, $response); + } + + /** + * Test that the correct event data is returned when handling a file submission for a quiz. + */ + public function test_create_submission_event_data_returns_correct_data_for_file_submission() { + global $DB; + + $this->resetAfterTest(); + + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $this->getDataGenerator()->enrol_user($this->student1->id, + $course->id, + $studentrole->id); + + $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course)); + $cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id, false, MUST_EXIST); + + // Log new user in. + $this->setUser($this->student1); + + $file = create_test_file(1, 1, 'mod_quiz', 'submissions'); + + // Create dummy link array data. + $linkarray = array( + "cmid" => $cm->id, + "userid" => $this->student1->id, + "file" => $file, + "content" => '', + "area" => 1 + ); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + $response = $tsquiz->create_submission_event_data($linkarray); + + $this->assertEquals('quiz_submitted', $response['eventtype']); + $this->assertEquals($cm->id, $response['contextinstanceid']); + $this->assertEquals($this->student1->id, $response['userid']); + $this->assertEquals(array($file->get_pathnamehash()), $response['other']['pathnamehashes']); + $this->assertEquals($linkarray['area'], $response['objectid']); + $this->assertEquals($this->student1->id, $response['relateduserid']); + $this->assertEquals('quiz', $response['other']['modulename']); + } + + /** + * Test that the correct event data is returned when handling a text submission for a quiz. + */ + public function test_create_submission_event_data_returns_correct_data_for_text_submission() { + global $DB; + + $this->resetAfterTest(); + + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $this->getDataGenerator()->enrol_user($this->student1->id, + $course->id, + $studentrole->id); + + $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course)); + $cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id, false, MUST_EXIST); + + $this->setUser($this->student1); + + // Create a question attempt, step and quiz attempt. + $questionattempt = $this->create_question_attempt(); + $this->create_question_attempt_step($questionattempt->id); + $this->create_quiz_attempt($questionattempt->questionusageid); + + // Create dummy link array data. + $linkarray = array( + "cmid" => $cm->id, + "userid" => $this->student1->id, + "content" => self::QUIZ_ANSWER_TEXT, + "area" => 1 + ); + + $tsquiz = new plagiarism_turnitinsim_quiz(); + + $response = $tsquiz->create_submission_event_data($linkarray); + $this->assertEquals('quiz_submitted', $response['eventtype']); + $this->assertEquals($cm->id, $response['contextinstanceid']); + $this->assertEquals($this->student1->id, $response['userid']); + $this->assertEquals($linkarray['area'], $response['objectid']); + $this->assertEquals($this->student1->id, $response['relateduserid']); + $this->assertEquals('quiz', $response['other']['modulename']); + } + + /** + * Helper method to create a question attempt. + * + * @return stdClass + * @throws dml_exception + */ + public function create_question_attempt() { + global $DB; + + $attempt = new stdClass(); + $attempt->questionusageid = 1; + $attempt->slot = 1; + $attempt->questionid = 1; + $attempt->maxmark = 100; + $attempt->minfraction = 50; + $attempt->timemodified = time(); + $attempt->responsesummary = self::QUIZ_ANSWER_TEXT; + $attempt->id = $DB->insert_record('question_attempts', $attempt); + + return $attempt; + } + + /** + * Helper method to create a question attempt step. + * + * @param int $questionattemptid - The ID of the question attempt. + * @throws dml_exception + */ + public function create_question_attempt_step($questionattemptid) { + global $DB; + + $step = new stdClass(); + $step->questionattemptid = $questionattemptid; + $step->sequencenumber = 1; + $step->state = 1; + $step->fraction = 100; + $step->timecreated = time(); + $step->userid = $this->student1->id; + $step->id = $DB->insert_record('question_attempt_steps', $step); + + return $step; + } + + /** + * Helper method to create a quiz attempt. + * + * @param int $questionusageid - A unique ID that maps to the questionusageid for a question attempt.. + * @throws dml_exception + */ + public function create_quiz_attempt($questionusageid) { + global $DB; + + $quizattempt = new stdClass(); + $quizattempt->quiz = self::MODULE_ID; + $quizattempt->userid = $this->student1->id; + $quizattempt->attempt = 1; + $quizattempt->uniqueid = $questionusageid; + $quizattempt->layout = '1,0'; + $quizattempt->currentpage = 0; + $quizattempt->preview = 0; + $quizattempt->state = 'finished'; + $quizattempt->timestart = time(); + $quizattempt->timefinish = time(); + $quizattempt->timemodified = time(); + $quizattempt->timemodifiedoffline = time(); + $quizattempt->id = $DB->insert_record('quiz_attempts', $quizattempt); + + return $quizattempt; + } +} \ No newline at end of file diff --git a/tests/classes/tssubmission_test.php b/tests/classes/tssubmission_test.php index 7d71208..99523e6 100644 --- a/tests/classes/tssubmission_test.php +++ b/tests/classes/tssubmission_test.php @@ -1225,6 +1225,7 @@ public function test_get_submission_details_file() { $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_QUEUED); $tssubmission->setidentifier($file->get_pathnamehash()); $tssubmission->settogenerate(1); + $tssubmission->setquizanswer(0); $tssubmission->update(); // Compare submission details. @@ -1282,7 +1283,8 @@ public function test_get_submission_details_text() { "cmid" => $cm->id, "userid" => $this->student1->id, "content" => $textcontent, - "objectid" => $submission->id + "objectid" => $submission->id, + "component" => "assign" ); // Compare submission details. @@ -1346,6 +1348,7 @@ public function test_set_generationtime_immediate() { $tssubmission->setsubmitter($this->student1->id); $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_QUEUED); $tssubmission->setidentifier($file->get_pathnamehash()); + $tssubmission->setquizanswer(0); $tssubmission->calculate_generation_time(); $tssubmission->update(); @@ -1415,6 +1418,7 @@ public function test_set_generationtime_immediate_duedate() { $tssubmission->setsubmitter($this->student1->id); $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_UPLOADED); $tssubmission->setidentifier($file->get_pathnamehash()); + $tssubmission->setquizanswer(0); $tssubmission->calculate_generation_time(); $tssubmission->update(); @@ -1494,6 +1498,7 @@ public function test_set_generationtime_duedate() { $tssubmission->setstatus(TURNITINSIM_SUBMISSION_STATUS_QUEUED); $tssubmission->setidentifier($file->get_pathnamehash()); $tssubmission->calculate_generation_time(); + $tssubmission->setquizanswer(0); $tssubmission->update(); // Compare submission details. diff --git a/tests/classes/workshop_test.php b/tests/classes/workshop_test.php index c121c4e..0fdf992 100644 --- a/tests/classes/workshop_test.php +++ b/tests/classes/workshop_test.php @@ -37,7 +37,7 @@ class workshop_test extends advanced_testcase { /** - * Sameple text used for unit testing a workshop. + * Sample text used for unit testing a workshop. */ const TEST_WORKSHOP_TEXT = 'Generated content'; diff --git a/tests/lib_test.php b/tests/lib_test.php index 55edc31..e309bdc 100644 --- a/tests/lib_test.php +++ b/tests/lib_test.php @@ -216,7 +216,7 @@ public function test_get_links_student_view_reports() { ); $plagiarismturnitinsim = new plagiarism_plugin_turnitinsim(); - $this->assertEquals('', $plagiarismturnitinsim->get_links($linkarray)); + $this->assertEquals('', $plagiarismturnitinsim->get_links($linkarray)); } /** @@ -270,6 +270,7 @@ public function test_get_links_with_submission() { $tssubmission->setoverallscore(100); $tssubmission->settype(TURNITINSIM_SUBMISSION_TYPE_FILE); $tssubmission->settogenerate(1); + $tssubmission->setquizanswer(0); $tssubmission->update(); // The HTML returned should contain the queued status and a Tii icon. @@ -524,7 +525,9 @@ public function test_print_disclosure_not_display_latest() { // Verify EULA is not output. $plagiarismturnitinsim = new plagiarism_plugin_turnitinsim(); - $this->assertEquals('', $plagiarismturnitinsim->print_disclosure($this->cm->id)); + $this->assertContains( + get_string('eulaalreadyaccepted', 'plagiarism_turnitinsim'), + $plagiarismturnitinsim->print_disclosure($this->cm->id)); } /** @@ -554,7 +557,9 @@ public function test_print_disclosure_eula_not_displayed_if_not_required() { // Verify EULA is not output. $plagiarismturnitinsim = new plagiarism_plugin_turnitinsim(); - $this->assertEquals('', $plagiarismturnitinsim->print_disclosure($this->cm->id)); + $this->assertContains( + get_string('eulanotrequired', 'plagiarism_turnitinsim'), + $plagiarismturnitinsim->print_disclosure($this->cm->id)); } /** diff --git a/version.php b/version.php index 56efc12..82cd46f 100644 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2020072101; +$plugin->version = 2020092301; $plugin->release = "v1.2"; $plugin->requires = 2017051500; $plugin->component = 'plagiarism_turnitinsim';