From 2ca771a6863bda71573d181dc550457d96f92387 Mon Sep 17 00:00:00 2001 From: Jane Adelmann Date: Thu, 12 May 2022 20:17:28 +0300 Subject: [PATCH] Quiz and Forum support --- classes/observer.php | 29 + classes/plagiarism_pchkorg_api_provider.php | 55 ++ classes/task/send_submissions.php | 2 +- classes/task/update_reports.php | 2 +- db/events.php | 8 + form/plagiarism_pchkorg_setup_form.php | 14 + lang/en/plagiarism_pchkorg.php | 2 + lib.php | 827 ++++++++++++++------ version.php | 8 +- 9 files changed, 721 insertions(+), 226 deletions(-) diff --git a/classes/observer.php b/classes/observer.php index 12ed4cb..19bdafe 100644 --- a/classes/observer.php +++ b/classes/observer.php @@ -85,4 +85,33 @@ class plagiarism_pchkorg_observer { $plugin = new plagiarism_plugin_pchkorg(); $plugin->event_handler($eventdata); } + + /** + * Handle the quiz attempt_submitted event. + * @param \mod_quiz\event\attempt_submitted $event + */ + public static function quiz_submitted( + \mod_quiz\event\attempt_submitted $event) { + $eventdata = $event->get_data(); + $eventdata['eventtype'] = 'quiz_submitted'; + $eventdata['other']['modulename'] = 'quiz'; + + $plugin = new plagiarism_plugin_pchkorg(); + $plugin->event_handler($eventdata); + } + + /** + * Handle the forum reply updated event. + * @param \mod_forum\event\assessable_uploaded $event + */ + public static function forum_assessable_uploaded( + \mod_forum\event\assessable_uploaded$event + ) { + $eventdata = $event->get_data(); + $eventdata['eventtype'] = 'forum_attachment'; + $eventdata['other']['modulename'] = 'forum'; + + $plugin = new plagiarism_plugin_pchkorg(); + $plugin->event_handler($eventdata); + } } diff --git a/classes/plagiarism_pchkorg_api_provider.php b/classes/plagiarism_pchkorg_api_provider.php index 89e686c..3d3a484 100644 --- a/classes/plagiarism_pchkorg_api_provider.php +++ b/classes/plagiarism_pchkorg_api_provider.php @@ -78,6 +78,61 @@ class plagiarism_pchkorg_api_provider { $this->endpoint = $endpoint; } + /** + * Send text for originality check. + * + * @param $authorhash + * @param $cousereid + * @param $assignmentid + * @param $assignmentname + * @param $submissionid + * @param $attachmentid + * @param $content + * @param $mime + * @param $filename + * + * @return |null + */ + public function general_send_check( + $authorhash, + $cousereid, + $assignmentid, + $assignmentname, + $submissionid, + $attachmentid, + $content, + $mime, + $filename, + $filters = array() + ) { + if ($this->is_group_token()) { + return $this->send_group_text( + $authorhash, + $cousereid, + $assignmentid, + $assignmentname, + $submissionid, + $attachmentid, + $content, + $mime, + $filename, + $filters + ); + } else { + return $this->send_text( + $cousereid, + $assignmentid, + $assignmentname, + $submissionid, + $attachmentid, + $content, + $mime, + $filename, + $filters + ); + } + } + /** * Send text for originality check. * diff --git a/classes/task/send_submissions.php b/classes/task/send_submissions.php index 5575634..c989c7d 100644 --- a/classes/task/send_submissions.php +++ b/classes/task/send_submissions.php @@ -26,7 +26,7 @@ namespace plagiarism_pchkorg\task; defined('MOODLE_INTERNAL') || die(); /** - * Send queued submissions to Turnitin. + * Send queued submissions. */ class send_submissions extends \core\task\scheduled_task { diff --git a/classes/task/update_reports.php b/classes/task/update_reports.php index 49881a5..108775d 100644 --- a/classes/task/update_reports.php +++ b/classes/task/update_reports.php @@ -26,7 +26,7 @@ namespace plagiarism_pchkorg\task; defined('MOODLE_INTERNAL') || die(); /** - * Update report Scores from Turnitin. + * Update report. */ class update_reports extends \core\task\scheduled_task { diff --git a/db/events.php b/db/events.php index 3a763a6..afcfdd1 100644 --- a/db/events.php +++ b/db/events.php @@ -40,4 +40,12 @@ $observers = array ( 'eventname' => '\core\event\course_module_deleted', 'callback' => 'plagiarism_pchkorg_observer::course_module_deleted' ), + array( + 'eventname' => '\mod_quiz\event\attempt_submitted', + 'callback' => 'plagiarism_pchkorg_observer::quiz_submitted', + ), + array( + 'eventname' => '\mod_forum\event\assessable_uploaded', + 'callback' => 'plagiarism_pchkorg_observer::forum_assessable_uploaded', + ), ); diff --git a/form/plagiarism_pchkorg_setup_form.php b/form/plagiarism_pchkorg_setup_form.php index 0d8bd73..cb0aeda 100644 --- a/form/plagiarism_pchkorg_setup_form.php +++ b/form/plagiarism_pchkorg_setup_form.php @@ -68,6 +68,20 @@ class plagiarism_pchkorg_setup_form extends moodleform { $mform->addRule('pchkorg_min_percent', get_string('pchkorg_min_percent_range', 'plagiarism_pchkorg'), 'check_pchkorg_min_percent'); $mform->setType('pchkorg_min_percent', PARAM_INT); + $mform->addElement( + 'select', + 'pchkorg_enable_quiz', + get_string('pchkorg_enable_quiz', 'plagiarism_pchkorg'), + array(get_string('no'), get_string('yes')) + ); + + $mform->addElement( + 'select', + 'pchkorg_enable_forum', + get_string('pchkorg_enable_forum', 'plagiarism_pchkorg'), + array(get_string('no'), get_string('yes')) + ); + $this->add_action_buttons(true); } diff --git a/lang/en/plagiarism_pchkorg.php b/lang/en/plagiarism_pchkorg.php index f09034d..bfc2101 100644 --- a/lang/en/plagiarism_pchkorg.php +++ b/lang/en/plagiarism_pchkorg.php @@ -42,6 +42,8 @@ $string['pchkorg_min_percent_range'] = 'Must be between 0 and 99'; $string['pchkorg_exclude_self_plagiarism'] = 'Exclude self-plagiarism'; $string['pchkorg_include_referenced'] = 'Include References'; $string['pchkorg_include_citation'] = 'Include Quotes'; +$string['pchkorg_enable_quiz'] = 'Enable PlagiarismCheck in Quizzes'; +$string['pchkorg_enable_forum'] = 'Enable PlagiarismCheck in Forum Activity'; $string['pchkorg_disclosure'] = 'Submission will be sent to PlagiarismCheck.org for check.
By submitting assignment I agree with Terms & Conditions diff --git a/lib.php b/lib.php index 1156527..c3353d3 100644 --- a/lib.php +++ b/lib.php @@ -39,10 +39,140 @@ function pchkorg_check_pchkorg_min_percent($value) return 0 <= $value && $value < 100; } +function plagiarism_pchkorg_coursemodule_standard_elements($formwrapper, $mform) +{ + $context = context_course::instance($formwrapper->get_course()->id); + $modulename = $formwrapper->get_current()->modulename; + $allowedmodules = array('assign', 'mod_assign'); + if (!$context || !isset($modulename)) { + return; + } + global $DB; + + $pchkorgconfigmodel = new plagiarism_pchkorg_config_model(); + + $config = $pchkorgconfigmodel->get_system_config('pchkorg_use'); + $enabled = has_capability(capability::ENABLE, $context); + if ( '1' === $pchkorgconfigmodel->get_system_config('pchkorg_enable_quiz')) { + $allowedmodules[] = 'quiz'; + } + if ( '1' === $pchkorgconfigmodel->get_system_config('pchkorg_enable_forum')) { + $allowedmodules[] = 'forum'; + } + if ('1' == $config && $enabled) { + if (!in_array($modulename, $allowedmodules, true)) { + return; + } + $defaultcmid = null; + $cm = optional_param('update', $defaultcmid, PARAM_INT); + $minpercent = $pchkorgconfigmodel->get_system_config('pchkorg_min_percent'); + + if (!isset($mform->exportValues()['pchkorg_exclude_self_plagiarism']) + || is_null($mform->exportValues()['pchkorg_exclude_self_plagiarism'])) { + $mform->setDefault('pchkorg_exclude_self_plagiarism', 1); + } + if (!isset($mform->exportValues()['pchkorg_include_referenced']) + || is_null($mform->exportValues()['pchkorg_include_referenced'])) { + $mform->setDefault('pchkorg_include_referenced', 0); + } + if (!isset($mform->exportValues()['pchkorg_include_citation']) + || is_null($mform->exportValues()['pchkorg_include_citation'])) { + $mform->setDefault('pchkorg_include_citation', 0); + } + + if (null === $cm) { + if (!isset($mform->exportValues()['pchkorg_module_use']) + || is_null($mform->exportValues()['pchkorg_module_use'])) { + $mform->setDefault('pchkorg_module_use', '1'); + } + } else { + $records = $DB->get_records('plagiarism_pchkorg_config', array( + 'cm' => $cm, + )); + if (!empty($records)) { + foreach ($records as $record) { + $mform->setDefault($record->name, $record->value); + } + } + } + $mform->addElement( + 'header', + 'plagiarism_pchkorg', + get_string('pluginname', 'plagiarism_pchkorg') + ); + $mform->addElement( + 'select', + 'pchkorg_module_use', + get_string('pchkorg_module_use', 'plagiarism_pchkorg'), + array(get_string('no'), get_string('yes')) + ); + $mform->addHelpButton('pchkorg_module_use', 'pchkorg_module_use', 'plagiarism_pchkorg'); + + $canchangeminpercent = has_capability(capability::CHANGE_MIN_PERCENT_FILTER, $context); + if ($canchangeminpercent) { + $dissabledattribute = ''; + } else { + $dissabledattribute = 'disabled="disabled"'; + } + $mform->registerRule( + 'check_pchkorg_min_percent', + 'callback', + 'pchkorg_check_pchkorg_min_percent' + ); + $label = get_string('pchkorg_min_percent', 'plagiarism_pchkorg'); + if (!empty($minpercent)) { + $label = \str_replace('X%', $minpercent . '%', $label); + } + + $mform->addElement( + 'text', + 'pchkorg_min_percent', + $label, + $dissabledattribute + ); + $mform->addHelpButton('pchkorg_min_percent', 'pchkorg_min_percent', 'plagiarism_pchkorg'); + $mform->addRule('pchkorg_min_percent', null, 'text', null, 'client'); + $mform->addRule( + 'pchkorg_min_percent', + get_string('pchkorg_min_percent_range', 'plagiarism_pchkorg'), + 'check_pchkorg_min_percent' + ); + $mform->setType('pchkorg_min_percent', PARAM_INT); + + $mform->addElement( + 'select', + 'pchkorg_exclude_self_plagiarism', + get_string('pchkorg_exclude_self_plagiarism', 'plagiarism_pchkorg'), + array(get_string('no'), get_string('yes')) + ); + + $mform->addElement( + 'select', + 'pchkorg_include_referenced', + get_string('pchkorg_include_referenced', 'plagiarism_pchkorg'), + array(get_string('no'), get_string('yes')) + ); + + $mform->addElement( + 'select', + 'pchkorg_include_citation', + get_string('pchkorg_include_citation', 'plagiarism_pchkorg'), + array(get_string('no'), get_string('yes')) + ); + } +} + +function plagiarism_pchkorg_coursemodule_edit_post_actions($data, $course) +{ + +} + /** * Class plagiarism_plugin_pchkorg */ class plagiarism_plugin_pchkorg extends plagiarism_plugin { + + /** * hook to allow plagiarism specific information to be displayed beside a submission. * @@ -51,8 +181,7 @@ class plagiarism_plugin_pchkorg extends plagiarism_plugin { * */ public function get_links($linkarray) { - - global $DB, $USER; + global $DB, $USER, $PAGE; $pchkorgconfigmodel = new plagiarism_pchkorg_config_model(); $apitoken = $pchkorgconfigmodel->get_system_config('pchkorg_token'); @@ -76,8 +205,17 @@ class plagiarism_plugin_pchkorg extends plagiarism_plugin { if ('1' !== $config) { return ''; } - $context = null; + $component = !empty($linkarray['component']) ? $linkarray['component'] : ''; + if ($cmid === null && $component == 'qtype_essay' && !empty($linkarray['area'])) { + $questions = question_engine::load_questions_usage_by_activity($linkarray['area']); + + $context = $questions->get_owning_context(); + if ($cmid === null && $context->contextlevel == CONTEXT_MODULE) { + $cmid = $context->instanceid; + } + } + if (!empty($cmid)) { $context = context_module::instance($cmid);// Get context of course. } @@ -118,10 +256,16 @@ class plagiarism_plugin_pchkorg extends plagiarism_plugin { } else { $where->fileid = $file->get_id(); } - $filerecords = $DB->get_records('plagiarism_pchkorg_files', (array) $where, 'id', '*', 0, 1); + if (!$filerecords && $file === null) { + $where->signature = sha1(trim(strip_tags($linkarray['content']))); + $where->fileid = null; + $filerecords = $DB->get_records('plagiarism_pchkorg_files', (array) $where, + 'id', '*', 0, 1); + } + if ($filerecords) { $filerecord = end($filerecords); @@ -132,7 +276,6 @@ class plagiarism_plugin_pchkorg extends plagiarism_plugin { if ($filerecord->state == 5) { $action = $apiprovider->get_report_action($filerecord->textid); $reporttoken = $apiprovider->generate_api_token(); - $formid = 'plagiarism_pchkorg_report_id_' . $filerecord->id; $score = $filerecord->score; $title = sprintf(get_string('pchkorg_label_title', 'plagiarism_pchkorg'), $filerecord->textid, @@ -146,25 +289,94 @@ class plagiarism_plugin_pchkorg extends plagiarism_plugin { } else { $color = '#f04343'; } + $jsdata = array( + 'id' => $filerecord->id, + 'title' => $title, + 'action' => $action, + 'token' => $reporttoken, + 'image' => $imgsrc, + 'label' => $label, + 'color' => $color + ); + static $isjsfuncinjected = false; + if (!$isjsfuncinjected) { + $isjsfuncinjected = true; + $PAGE->requires->js_amd_inline( + " +window.plagiarism_check_data = []; +window.plagiarism_check_full_report = function (action, token) { + const form = document.createElement('form'); + const element1 = document.createElement('input'); + const element2 = document.createElement('input'); + + form.method = 'POST'; + form.target = '_blank'; + form.action = action; + + element1.value = 'moodle'; + element1.name = 'lms-type'; + element1.type = 'hidden'; + form.appendChild(element1); + + element2.value = token; + element2.name = 'token'; + element2.type = 'hidden'; + form.appendChild(element2); + + document.body.appendChild(form); + + form.submit(); +}; +window.onload = function () { + var spans = window.document.getElementsByClassName('plagiarism-pchkorg-widget'); + for (var span of spans) { + for (var classname of span.classList) { + if (classname.includes('plagiarism-pchkorg-widget-id-')) { + var id = classname.replace('plagiarism-pchkorg-widget-id-', ''); + if (id) { + for (var data of window.plagiarism_check_data) { + if (data.id == id) { + var a = document.createElement('a'); + a.setAttribute('href', '#'); + a.setAttribute('title', data.title); + a.style.padding = '5px 3px'; + a.style.textDecoration = 'none'; + a.style.backgroundColor = data.color; + a.style.color = 'black'; + a.style.cursor = 'pointer'; + a.style.borderRadius = '3px 3px 3px 3px'; + a.style.margin = '4px'; + a.style.display = 'inline-block'; + a.onclick = function() { + window.plagiarism_check_full_report(data.action, data.token); + return false; + }; + var label = document.createTextNode(data.label); + var img = document.createElement('img'); + img.setAttribute('alt', 'PlagiarismCheck.org'); + img.setAttribute('src', data.image); + img.setAttribute('width', '20'); + a.appendChild(img); + a.appendChild(label); + span.appendChild(a); + break; + } + } + } + break; + } + } + } +} + " + ); + } + + $PAGE->requires->js_amd_inline("window.plagiarism_check_data.push(".json_encode($jsdata).")"); + return ' - - logo - ' . $label . ' -
- - -
'; + '; } else if ($filerecord->state == 10) { $label = get_string('pchkorg_label_queued', 'plagiarism_pchkorg'); return ' @@ -176,7 +388,7 @@ border-radius: 3px 3px 3px 3px; margin: 4px; display: inline-block;" href="#" class="plagiarism_pchkorg_report_id_score"> - logo + logo ' . $label . ' '; } else if ($filerecord->state == 12) { @@ -190,7 +402,7 @@ border-radius: 3px 3px 3px 3px; margin: 4px; display: inline-block;" href="#" class="plagiarism_pchkorg_report_id_score"> - logo + logo ' . $label . ' '; } @@ -265,128 +477,6 @@ display: inline-block;" } } - /** - * - * Build plugin settings form. - * - * @param object $mform - * @param object $context - * @param string $modulename - * @throws coding_exception - * @throws dml_exception - */ - public function get_form_elements_module($mform, $context, $modulename = '') { - if (!$context || !isset($modulename) || 'mod_assign' !== $modulename) { - return; - } - global $DB; - - $pchkorgconfigmodel = new plagiarism_pchkorg_config_model(); - - $config = $pchkorgconfigmodel->get_system_config('pchkorg_use'); - $enabled = has_capability(capability::ENABLE, $context); - - if ('1' == $config && $enabled) { - $defaultcmid = null; - $cm = optional_param('update', $defaultcmid, PARAM_INT); - $minpercent = $pchkorgconfigmodel->get_system_config('pchkorg_min_percent'); - - if (!isset($mform->exportValues()['pchkorg_exclude_self_plagiarism']) - || is_null($mform->exportValues()['pchkorg_exclude_self_plagiarism'])) { - $mform->setDefault('pchkorg_exclude_self_plagiarism', 1); - } - if (!isset($mform->exportValues()['pchkorg_include_referenced']) - || is_null($mform->exportValues()['pchkorg_include_referenced'])) { - $mform->setDefault('pchkorg_include_referenced', 0); - } - if (!isset($mform->exportValues()['pchkorg_include_citation']) - || is_null($mform->exportValues()['pchkorg_include_citation'])) { - $mform->setDefault('pchkorg_include_citation', 0); - } - - if (null === $cm) { - if (!isset($mform->exportValues()['pchkorg_module_use']) - || is_null($mform->exportValues()['pchkorg_module_use'])) { - $mform->setDefault('pchkorg_module_use', '1'); - } - } else { - $records = $DB->get_records('plagiarism_pchkorg_config', array( - 'cm' => $cm, - )); - if (!empty($records)) { - foreach ($records as $record) { - $mform->setDefault($record->name, $record->value); - } - } - } - - $mform->addElement( - 'header', - 'plagiarism_pchkorg', - get_string('pluginname', 'plagiarism_pchkorg') - ); - $mform->addElement( - 'select', - 'pchkorg_module_use', - get_string('pchkorg_module_use', 'plagiarism_pchkorg'), - array(get_string('no'), get_string('yes')) - ); - $mform->addHelpButton('pchkorg_module_use', 'pchkorg_module_use', 'plagiarism_pchkorg'); - - $canchangeminpercent = has_capability(capability::CHANGE_MIN_PERCENT_FILTER, $context); - if ($canchangeminpercent) { - $dissabledattribute = ''; - } else { - $dissabledattribute = 'disabled="disabled"'; - } - $mform->registerRule( - 'check_pchkorg_min_percent', - 'callback', - 'pchkorg_check_pchkorg_min_percent' - ); - $label = get_string('pchkorg_min_percent', 'plagiarism_pchkorg'); - if (!empty($minpercent)) { - $label = \str_replace('X%', $minpercent . '%', $label); - } - - $mform->addElement( - 'text', - 'pchkorg_min_percent', - $label, - $dissabledattribute - ); - $mform->addHelpButton('pchkorg_min_percent', 'pchkorg_min_percent', 'plagiarism_pchkorg'); - $mform->addRule('pchkorg_min_percent', null, 'text', null, 'client'); - $mform->addRule( - 'pchkorg_min_percent', - get_string('pchkorg_min_percent_range', 'plagiarism_pchkorg'), - 'check_pchkorg_min_percent' - ); - $mform->setType('pchkorg_min_percent', PARAM_INT); - - $mform->addElement( - 'select', - 'pchkorg_exclude_self_plagiarism', - get_string('pchkorg_exclude_self_plagiarism', 'plagiarism_pchkorg'), - array(get_string('no'), get_string('yes')) - ); - - $mform->addElement( - 'select', - 'pchkorg_include_referenced', - get_string('pchkorg_include_referenced', 'plagiarism_pchkorg'), - array(get_string('no'), get_string('yes')) - ); - - $mform->addElement( - 'select', - 'pchkorg_include_citation', - get_string('pchkorg_include_citation', 'plagiarism_pchkorg'), - array(get_string('no'), get_string('yes')) - ); - } - } - /** * hook to allow a disclosure to be printed notifying users what will happen with their submission. * @@ -399,20 +489,28 @@ display: inline-block;" if (empty($cmid)) { return ''; } - // Get course details. $cm = get_coursemodule_from_id('', $cmid); - - if (!$cm || $cm->modname != 'assign') { + if (!$cm) { return ''; } $configmodel = new plagiarism_pchkorg_config_model(); - $enabled = $configmodel->get_system_config('pchkorg_use'); if ($enabled !== '1') { return ''; } + $modulename = $cm->modname; + $allowedmodules = array('assign', 'mod_assign'); + if ($configmodel->get_system_config('pchkorg_enable_quiz')) { + $allowedmodules[] = 'quiz'; + } + if ($configmodel->get_system_config('pchkorg_enable_forum')) { + $allowedmodules[] = 'forum'; + } + if (!in_array($modulename, $allowedmodules, true)) { + return ''; + } if (!$configmodel->is_enabled_for_module($cmid)) { return ''; @@ -446,26 +544,33 @@ display: inline-block;" public function event_handler($eventdata) { global $USER, $DB; + $modulename = $eventdata['other']['modulename']; + $allowedmodules = array('assign', 'mod_assign'); // We support only assign module so just ignore all other. - if ($eventdata['other']['modulename'] !== 'assign') { - return true; - } - $pchkorgconfigmodel = new plagiarism_pchkorg_config_model(); // Token is needed for API auth. $apitoken = $pchkorgconfigmodel->get_system_config('pchkorg_token'); $apiprovider = new plagiarism_pchkorg_api_provider($apitoken); - // SQL will be called only once, result is static. $config = $pchkorgconfigmodel->get_system_config('pchkorg_use'); if ('1' !== $config) { return true; } + if ('1' === $pchkorgconfigmodel->get_system_config('pchkorg_enable_quiz')) { + $allowedmodules[] = 'quiz'; + } + if ('1' === $pchkorgconfigmodel->get_system_config('pchkorg_enable_forum')) { + $allowedmodules[] = 'forum'; + } + if (!in_array($modulename, $allowedmodules, true)) { + return true; + } // Receive couser moudle id. $cmid = $eventdata['contextinstanceid']; // Remove the event if the course module no longer exists. $cm = get_coursemodule_from_id($eventdata['other']['modulename'], $cmid); + if (!$cm) { return true; } @@ -499,13 +604,176 @@ display: inline-block;" } } + if ($eventdata['other']['modulename'] === 'forum' + && $eventdata['eventtype'] === 'forum_attachment') { + if (!empty($eventdata['other']['content'])) { + $content = trim(strip_tags($eventdata['other']['content'])); + if (strlen($content) > 80) { + $signature = sha1($content); + $filesconditions = array( + 'signature' => $signature, + 'cm' => $cmid, + 'userid' => $USER->id, + 'itemid' => $eventdata['objectid'] + ); + $oldfile = $DB->get_record('plagiarism_pchkorg_files', $filesconditions); + if (!$oldfile) { + $filerecord = new \stdClass(); + $filerecord->fileid = null; + $filerecord->cm = $cmid; + $filerecord->userid = $USER->id; + $filerecord->textid = null; + $filerecord->state = 10; + $filerecord->created_at = time(); + $filerecord->itemid = $eventdata['objectid']; + $filerecord->signature = $signature; + + $DB->insert_record('plagiarism_pchkorg_files', $filerecord); + } + } + } + if (!empty($eventdata['other']['pathnamehashes'])) { + foreach ($eventdata['other']['pathnamehashes'] as $pathnamehash) { + $file = get_file_storage()->get_file_by_hash($pathnamehash); + if (!$file) { + // We can not find file so we do not send it in queue. + continue; + } else { + try { + // Check that we can fetch content without exception. + $content = $file->get_content(); + } catch (Exception $e) { + // No we can not. + continue; + } + } + if ($file->get_filename() === '.') { + continue; + } + $filemime = $file->get_mimetype(); + + // File type is not supported. + if (!$apiprovider->is_supported_mime($filemime)) { + continue; + } + $signature = sha1($content); + $filesconditions = array( + 'fileid' => $file->get_id() + ); + $oldfile = $DB->get_record('plagiarism_pchkorg_files', $filesconditions); + if (!$oldfile) { + $filerecord = new \stdClass(); + $filerecord->fileid = $file->get_id(); + $filerecord->cm = $cmid; + $filerecord->userid = $USER->id; + $filerecord->textid = null; + $filerecord->state = 10; + $filerecord->created_at = time(); + $filerecord->itemid = $eventdata['objectid']; + $filerecord->signature = $signature; + + $DB->insert_record('plagiarism_pchkorg_files', $filerecord); + } + } + } + + return true; + } + + if ($eventdata['other']['modulename'] === 'quiz' + && $eventdata['eventtype'] === 'quiz_submitted') { + + $attempt = quiz_attempt::create($eventdata['objectid']); + foreach ($attempt->get_slots() as $slot) { + $questionattempt = $attempt->get_question_attempt($slot); + $qtype = $questionattempt->get_question()->qtype; + if ($qtype instanceof qtype_essay) { + $attachments = $questionattempt->get_last_qt_files('attachments', $eventdata['contextid']); + $content = $questionattempt->get_response_summary(); + if (strlen($content) > 80) { + $signature = sha1($content); + $filesconditions = array( + 'signature' => $signature, + 'cm' => $cmid, + 'userid' => $USER->id, + 'itemid' => $eventdata['objectid'] + ); + + $oldfile = $DB->get_record('plagiarism_pchkorg_files', $filesconditions); + if ($oldfile) { + // There is the same check in database, so we can skip this one. + return true; + } + + $filerecord = new \stdClass(); + $filerecord->fileid = null; + $filerecord->cm = $cmid; + $filerecord->userid = $USER->id; + $filerecord->textid = null; + $filerecord->state = 10; + $filerecord->created_at = time(); + $filerecord->itemid = $eventdata['objectid']; + $filerecord->signature = $signature; + + $DB->insert_record('plagiarism_pchkorg_files', $filerecord); + } + foreach ($attachments as $pathnamehash => $file) { + if (!$file) { + // We can not find file so we do not send it in queue. + continue; + } else { + try { + // Check that we can fetch content without exception. + $content = $file->get_content(); + } catch (Exception $e) { + // No we can not. + continue; + } + } + if ($file->get_filename() === '.') { + continue; + } + $filemime = $file->get_mimetype(); + + // File type is not supported. + if (!$apiprovider->is_supported_mime($filemime)) { + continue; + } + $signature = sha1($content); + $filesconditions = array( + 'fileid' => $file->get_id() + ); + $oldfile = $DB->get_record('plagiarism_pchkorg_files', $filesconditions); + if (!$oldfile) { + $filerecord = new \stdClass(); + $filerecord->fileid = $file->get_id(); + $filerecord->cm = $cmid; + $filerecord->userid = $USER->id; + $filerecord->textid = null; + $filerecord->state = 10; + $filerecord->created_at = time(); + $filerecord->itemid = $eventdata['objectid']; + $filerecord->signature = $signature; + + $DB->insert_record('plagiarism_pchkorg_files', $filerecord); + } + } + } + } + } + // Get actual text content and files to be submitted for draft submissions. // As this won't be present in eventdata for certain event types. - if ($eventdata['other']['modulename'] == 'assign' && $eventdata['eventtype'] == "assessable_submitted") { + if ($eventdata['other']['modulename'] === 'assign' + && $eventdata['eventtype'] === 'assessable_submitted') { + // Get content. $moodlesubmission = $DB->get_record('assign_submission', array('id' => $eventdata['objectid']), 'id'); - if ($moodletextsubmission = $DB->get_record('assignsubmission_onlinetext', - array('submission' => $moodlesubmission->id), 'onlinetext')) { + + $moodletextsubmission = $DB->get_record('assignsubmission_onlinetext', + array('submission' => $moodlesubmission->id), 'onlinetext'); + + if ($moodletextsubmission) { $eventdata['other']['content'] = $moodletextsubmission->onlinetext; } @@ -561,7 +829,8 @@ display: inline-block;" // Queue text content to send to plagiarismcheck.org. // If there was an error when creating the assignment then still queue the submission so it can be saved as failed. - if (in_array($eventdata['eventtype'], array("content_uploaded", "assessable_submitted")) + if ($eventdata['other']['modulename'] === 'assign' + && in_array($eventdata['eventtype'], array("content_uploaded", "assessable_submitted")) && !empty($eventdata['other']['content'])) { $signature = sha1($eventdata['other']['content']); @@ -586,7 +855,6 @@ display: inline-block;" $filerecord->textid = null; $filerecord->state = 10; $filerecord->created_at = time(); - $filerecord->itemid = $eventdata['objectid']; $filerecord->signature = $signature; @@ -639,10 +907,16 @@ display: inline-block;" if ('1' !== $config) { return true; } - $filesconditions = array('state' => 10); - $moodlefiles = $DB->get_records('plagiarism_pchkorg_files', $filesconditions, - 'id', '*', 0, 20); + $moodlefiles = $DB->get_records( + 'plagiarism_pchkorg_files', + $filesconditions, + 'id', + '*', + 0, + 20 + ); + if ($moodlefiles) { $fs = get_file_storage(); foreach ($moodlefiles as $filedb) { @@ -676,59 +950,138 @@ display: inline-block;" if ($minpercent) { $filters['source_min_percent'] = $minpercent; } - if ($filedb->fileid === null) { - $moodletextsubmission = $DB->get_record('assignsubmission_onlinetext', - array('submission' => $filedb->itemid), '*'); - if ($moodletextsubmission) { - $content = $moodletextsubmission->onlinetext; - if ($apiprovider->is_group_token()) { - $textid = $apiprovider->send_group_text( - $apiprovider->user_email_to_hash($user->email), - $cm->course, - $cm->id, - $cm->name, - $moodletextsubmission->id, - $moodletextsubmission->id, - html_to_text($content, 75, false), - 'plain/text', - sprintf('%s-submussion.txt', $moodletextsubmission->id), - $filters, - ); - } else { - $textid = $apiprovider->send_text( - $cm->course, - $cm->id, - $cm->name, - $moodletextsubmission->id, - $moodletextsubmission->id, - html_to_text($content, 75, false), - 'plain/text', - sprintf('%s-submussion.txt', $moodletextsubmission->id), - $filters, - ); + + $agreementwhere = array( + 'cm' => 0, + 'name' => 'accepted_agreement', + 'value' => '1', + ); + $agreementaccepted = $DB->get_records('plagiarism_pchkorg_config', $agreementwhere); + if (empty($agreementaccepted)) { + $apiprovider->save_accepted_agreement($user->email); + $DB->insert_record('plagiarism_pchkorg_config', $agreementwhere); + } + + if ($cm->modname === 'quiz') { + if ($filedb->fileid === null) { + $questionanswers = $DB->get_records_sql( + "SELECT {question_attempts}.responsesummary " + ." FROM {question_attempts} " + ." INNER JOIN {question} on {question}.id = {question_attempts}.questionid " + ." WHERE {question_attempts}.questionusageid = ? AND {question}.qtype = 'essay' ", array( + $filedb->itemid + ) + ); + + foreach ($questionanswers as $questionanswer) { + $content = $questionanswer->responsesummary; + $signature = sha1($content); + if ($signature === $filedb->signature) { + $textid = $apiprovider->general_send_check( + $apiprovider->user_email_to_hash($user->email), + $cm->course, + $cm->id, + $cm->name, + $filedb->itemid, + null, + html_to_text($content, 75, false), + 'plain/text', + sprintf('%s-quiz.txt', $filedb->itemid), + $filters, + ); + break; + } } + } else { + $file = $fs->get_file_by_id($filedb->fileid); + // We can not receive file by id. + // Maybe file does not exist anymore. + // So we mark it as error and continue. + if (!$file || !is_object($file)) { + $filedbnew = new stdClass(); + $filedbnew->id = $filedb->id; + $filedbnew->attempt = $filedb->attempt + 1; + $filedbnew->state = 11; // Sending error. + + $DB->update_record('plagiarism_pchkorg_files', $filedbnew); + + continue; + } + $textid = $apiprovider->general_send_check( + $apiprovider->user_email_to_hash($user->email), + $cm->course, + $cm->id, + $cm->name, + $filedb->itemid, + $file->get_id(), + $file->get_content(), + $file->get_mimetype(), + $file->get_filename(), + $filters + ); } - } else { - $moodlesubmission = $DB->get_record('assign_submission', array('assignment' => $cm->instance, - 'userid' => $filedb->userid, 'id' => $filedb->itemid), 'id'); - $file = $fs->get_file_by_id($filedb->fileid); + } + if ($cm->modname === 'forum') { + if ($filedb->fileid === null) { + $post = $DB->get_record_sql( + "SELECT subject, message" + ." FROM {forum_posts}" + ." WHERE {forum_posts}.id = ?", array( + $filedb->itemid + ) + ); + if ($post) { + $subject = $post->subject; + $content = $post->message; + $signature = sha1($content); + $ismatched = false; + if ($signature === $filedb->signature) { + $ismatched = true; + } + if (!$ismatched) { + $signature = sha1(trim(strip_tags($content))); + if ($signature === $filedb->signature) { + $ismatched = true; + } + } - // We can not receive file by id. - // Maybe file does not exist anymore. - // So we mark it as error and continue. - if (!$file || !is_object($file)) { - $filedbnew = new stdClass(); - $filedbnew->id = $filedb->id; - $filedbnew->attempt = $filedb->attempt + 1; - $filedbnew->state = 11; // Sending error. + if ($ismatched) { + $textid = $apiprovider->general_send_check( + $apiprovider->user_email_to_hash($user->email), + $cm->course, + $cm->id, + $cm->name, + $subject, + null, + html_to_text($content, 75, false), + 'plain/text', + sprintf('%s-quiz.txt', $filedb->itemid), + $filters, + ); + } + } + } else { + $moodlesubmission = $DB->get_record('assign_submission', array( + 'assignment' => $cm->instance, + 'userid' => $filedb->userid, + 'id' => $filedb->itemid, + ), 'id'); + $file = $fs->get_file_by_id($filedb->fileid); - $DB->update_record('plagiarism_pchkorg_files', $filedbnew); + // We can not receive file by id. + // Maybe file does not exist anymore. + // So we mark it as error and continue. + if (!$file || !is_object($file)) { + $filedbnew = new stdClass(); + $filedbnew->id = $filedb->id; + $filedbnew->attempt = $filedb->attempt + 1; + $filedbnew->state = 11; // Sending error. - continue; - } + $DB->update_record('plagiarism_pchkorg_files', $filedbnew); - if ($apiprovider->is_group_token()) { - $textid = $apiprovider->send_group_text( + continue; + } + $textid = $apiprovider->general_send_check( $apiprovider->user_email_to_hash($user->email), $cm->course, $cm->id, @@ -740,19 +1093,53 @@ display: inline-block;" $file->get_filename(), $filters ); - } else { - $agreementwhere = array( - 'cm' => 0, - 'name' => 'accepted_agreement', - 'value' => '1' + } + } + if ($cm->modname === 'assign') { + if ($filedb->fileid === null) { + $moodletextsubmission = $DB->get_record( + 'assignsubmission_onlinetext', + array('submission' => $filedb->itemid), + '*' ); - $agreementaccepted = $DB->get_records('plagiarism_pchkorg_config', $agreementwhere); - if (empty($agreementaccepted)) { - $apiprovider->save_accepted_agreement($user->email); - $DB->insert_record('plagiarism_pchkorg_config', $agreementwhere); + if ($moodletextsubmission) { + $content = $moodletextsubmission->onlinetext; + $textid = $apiprovider->general_send_check( + $apiprovider->user_email_to_hash($user->email), + $cm->course, + $cm->id, + $cm->name, + $moodletextsubmission->id, + $moodletextsubmission->id, + html_to_text($content, 75, false), + 'plain/text', + sprintf('%s-submussion.txt', $moodletextsubmission->id), + $filters, + ); } + } else { + $moodlesubmission = $DB->get_record('assign_submission', array( + 'assignment' => $cm->instance, + 'userid' => $filedb->userid, + 'id' => $filedb->itemid, + ), 'id'); + $file = $fs->get_file_by_id($filedb->fileid); - $textid = $apiprovider->send_text( + // We can not receive file by id. + // Maybe file does not exist anymore. + // So we mark it as error and continue. + if (!$file || !is_object($file)) { + $filedbnew = new stdClass(); + $filedbnew->id = $filedb->id; + $filedbnew->attempt = $filedb->attempt + 1; + $filedbnew->state = 11; // Sending error. + + $DB->update_record('plagiarism_pchkorg_files', $filedbnew); + + continue; + } + $textid = $apiprovider->general_send_check( + $apiprovider->user_email_to_hash($user->email), $cm->course, $cm->id, $cm->name, diff --git a/version.php b/version.php index 6c20eec..b640ef1 100644 --- a/version.php +++ b/version.php @@ -26,11 +26,11 @@ defined('MOODLE_INTERNAL') || die(); if (!isset($plugin)) { $plugin = new stdClass(); } -$plugin->version = 2022050519; -$plugin->requires = 2017051500; // Requires Moodle 3.3 . -$plugin->release = 'v3.8.4'; -$plugin->maturity = MATURITY_STABLE; +$plugin->version = 2022052621; +$plugin->requires = 2020061501; // Requires Moodle 3.9 . +$plugin->release = 'v3.9.2'; $plugin->component = 'plagiarism_pchkorg'; +$plugin->maturity = MATURITY_STABLE; $plugin->dependencies = array( 'mod_assign' => ANY_VERSION, );