diff --git a/admin/settings/plugins.php b/admin/settings/plugins.php index 353377ae5814e..1beb39f58eab7 100644 --- a/admin/settings/plugins.php +++ b/admin/settings/plugins.php @@ -376,7 +376,17 @@ } } } - +if ($hassiteconfig && !empty($CFG->enableplagiarism)) { + $ADMIN->add('modules', new admin_category('plagiarism', get_string('plagiarism', 'plagiarism'))); + $temp = new admin_settingpage('plagiarismsettings', get_string('plagiarismsettings', 'plagiarism')); + $temp->add(new admin_setting_manageplagiarism()); + $ADMIN->add('plagiarism', $temp); + foreach (get_plugin_list('plagiarism') as $plugin => $plugindir) { + if (file_exists($plugindir.'/settings.php')) { + $ADMIN->add('plagiarism', new admin_externalpage('plagiarism'.$plugin, get_string($plugin, 'plagiarism_'.$plugin), "$CFG->wwwroot/plagiarism/$plugin/settings.php", 'moodle/site:config')); + } + } +} $ADMIN->add('reports', new admin_externalpage('comments', get_string('comments'), $CFG->wwwroot.'/comment/', 'moodle/site:viewreports')); /// Now add reports diff --git a/admin/settings/subsystems.php b/admin/settings/subsystems.php index e30f07ae97019..7998f47b26567 100644 --- a/admin/settings/subsystems.php +++ b/admin/settings/subsystems.php @@ -39,4 +39,6 @@ $optionalsubsystems->add(new admin_setting_configcheckbox('enableavailability', get_string('enableavailability','condition'), get_string('configenableavailability','condition'), 0)); + + $optionalsubsystems->add(new admin_setting_configcheckbox('enableplagiarism', get_string('enableplagiarism','plagiarism'), get_string('configenableplagiarism','plagiarism'), 0)); } diff --git a/course/modedit.php b/course/modedit.php index 3a7ae149b4458..4b5583891d365 100644 --- a/course/modedit.php +++ b/course/modedit.php @@ -29,6 +29,7 @@ require_once($CFG->libdir.'/gradelib.php'); require_once($CFG->libdir.'/completionlib.php'); require_once($CFG->libdir.'/conditionlib.php'); +require_once($CFG->libdir.'/plagiarismlib.php'); $add = optional_param('add', '', PARAM_ALPHA); // module name $update = optional_param('update', 0, PARAM_INT); @@ -560,6 +561,7 @@ rebuild_course_cache($course->id); grade_regrade_final_grades($course->id); + plagiarism_save_form_elements($fromform); //save plagiarism settings if (isset($fromform->submitbutton)) { redirect("$CFG->wwwroot/mod/$module->name/view.php?id=$fromform->coursemodule"); diff --git a/lang/en/plagiarism.php b/lang/en/plagiarism.php new file mode 100644 index 0000000000000..1acc76962d6e9 --- /dev/null +++ b/lang/en/plagiarism.php @@ -0,0 +1,9 @@ +nosave = true; + parent::__construct('plagiarismui', get_string('plagiarismsettings', 'plagiarism'), '', ''); + } + + /** + * Always returns true + * + * @return true + */ + public function get_setting() { + return true; + } + + /** + * Always returns true + * + * @return true + */ + public function get_defaultsetting() { + return true; + } + + /** + * Always returns '' and doesn't write anything + * + * @return string Always returns '' + */ + public function write_setting($data) { + // do not write any setting + return ''; + } + + /** + * Return XHTML to display control + * + * @param mixed $data Unused + * @param string $query + * @return string highlight + */ + public function output_html($data, $query='') { + global $CFG, $OUTPUT; + + // display strings + $txt = get_strings(array('settings', 'name')); + + $plagiarismplugins = get_plugin_list('plagiarism'); + if (empty($plagiarismplugins)) { + return get_string('nopluginsinstalled', 'plagiarism'); + } + + $return = $OUTPUT->heading(get_string('availableplugins', 'plagiarism'), 3, 'main'); + $return .= $OUTPUT->box_start('generalbox authsui'); + + $table = new html_table(); + $table->head = array($txt->name, $txt->settings); + $table->align = array('left', 'center'); + $table->data = array(); + $table->attributes['class'] = 'manageplagiarismtable generaltable'; + + // iterate through auth plugins and add to the display table + $authcount = count($plagiarismplugins); + foreach ($plagiarismplugins as $plugin => $dir) { + if (file_exists($dir.'/settings.php')) { + $displayname = "".get_string($plugin, 'plagiarism_'.$plugin).""; + // settings link + $settings = "wwwroot/plagiarism/$plugin/settings.php\">{$txt->settings}"; + // add a row to the table + $table->data[] =array($displayname, $settings); + } + } + $return .= html_writer::table($table); + $return .= get_string('configplagiarismplugins', 'plagiarism'); + $return .= $OUTPUT->box_end(); + return highlight($query, $return); + } +} /** * Special class for overview of external services diff --git a/lib/cronlib.php b/lib/cronlib.php index 799f2903d0df7..02afd379189b1 100644 --- a/lib/cronlib.php +++ b/lib/cronlib.php @@ -116,6 +116,10 @@ function cron_run() { } mtrace('Finished blocks'); + //now do plagiarism checks + require_once($CFG->libdir.'/plagiarismlib.php'); + plagiarism_cron(); + mtrace("Starting quiz reports"); if ($reports = $DB->get_records_select('quiz_report', "cron > 0 AND ((? - lastcron) > cron)", array($timenow))) { foreach ($reports as $report) { diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 6e876c839c531..d5682551a8ec6 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -6917,6 +6917,7 @@ function get_core_subsystems() { 'notes' => 'notes', 'pagetype' => NULL, 'pix' => NULL, + 'plagiarism' => 'plagiarism', 'portfolio' => 'portfolio', 'publish' => 'course/publish', 'question' => 'question', @@ -6973,6 +6974,7 @@ function get_plugin_types($fullpaths=true) { 'portfolio' => 'portfolio', 'qtype' => 'question/type', 'qformat' => 'question/format', + 'plagiarism' => 'plagiarism', 'theme' => 'theme'); // this is a bit hacky, themes may be in dataroot too $mods = get_plugin_list('mod'); diff --git a/lib/plagiarismlib.php b/lib/plagiarismlib.php new file mode 100644 index 0000000000000..b8c854626ee7c --- /dev/null +++ b/lib/plagiarismlib.php @@ -0,0 +1,170 @@ +. + +/** + * plagiarismlib.php - Contains core Plagiarism related functions. + * + * @since 2.0 + * @package moodlecore + * @subpackage plagiarism + * @copyright 2010 Dan Marsden http://danmarsden.com + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +///// GENERIC PLAGIARISM FUNCTIONS //////////////////////////////////////////////////// + +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page +} + +/** + * displays the similarity score and provides a link to the full report if allowed. + * + * @param object $linkarray contains all relevant information for the plugin to generate a link + * @return string - url to allow login/viewing of a similarity report + */ +function plagiarism_get_links($linkarray) { + global $CFG; + if (empty($CFG->enableplagiarism)) { + return ''; + } + $plagiarismplugins = plagiarism_load_available_plugins(); + $output = ''; + foreach($plagiarismplugins as $plugin => $dir) { + require_once($dir.'/lib.php'); + $plagiarismclass = "plagiarism_plugin_$plugin"; + $plagiarismplugin = new $plagiarismclass; + $output .= $plagiarismplugin->get_links($linkarray); + } + return $output; +} + +/** + * saves/updates plagiarism settings from a modules config page - called by course/modedit.php + * + * @param object $data - form data + */ +function plagiarism_save_form_elements($data) { + global $CFG; + if (empty($CFG->enableplagiarism)) { + return ''; + } + $plagiarismplugins = plagiarism_load_available_plugins(); + foreach($plagiarismplugins as $plugin => $dir) { + require_once($dir.'/lib.php'); + $plagiarismclass = "plagiarism_plugin_$plugin"; + $plagiarismplugin = new $plagiarismclass; + $plagiarismplugin->save_form_elements($data); + } +} + +/** + * adds the list of plagiarism settings to a form - called inside modules that have enabled plagiarism + * + * @param object $mform - Moodle form object + * @param object $context - context object + */ +function plagiarism_get_form_elements_module($mform, $context) { + global $CFG; + if (empty($CFG->enableplagiarism)) { + return ''; + } + $plagiarismplugins = plagiarism_load_available_plugins(); + foreach($plagiarismplugins as $plugin => $dir) { + require_once($dir.'/lib.php'); + $plagiarismclass = "plagiarism_plugin_$plugin"; + $plagiarismplugin = new $plagiarismclass; + $plagiarismplugin->get_form_elements_module($mform, $context); + } +} +/** + * updates the status of all files within a module + * + * @param object $course - full Course object + * @param object $cm - full cm object + */ +function plagiarism_update_status($course, $cm) { + global $CFG; + if (empty($CFG->enableplagiarism)) { + return ''; + } + $plagiarismplugins = plagiarism_load_available_plugins(); + foreach($plagiarismplugins as $plugin => $dir) { + require_once($dir.'/lib.php'); + $plagiarismclass = "plagiarism_plugin_$plugin"; + $plagiarismplugin = new $plagiarismclass; + $plagiarismplugin->update_status($course, $cm); + } +} + +/** +* Function that prints the student disclosure notifying that the files will be checked for plagiarism +* @param integer $cmid - the cmid of this module +*/ +function plagiarism_print_disclosure($cmid) { + global $CFG; + if (empty($CFG->enableplagiarism)) { + return ''; + } + $plagiarismplugins = plagiarism_load_available_plugins(); + foreach($plagiarismplugins as $plugin => $dir) { + require_once($dir.'/lib.php'); + $plagiarismclass = "plagiarism_plugin_$plugin"; + $plagiarismplugin = new $plagiarismclass; + $plagiarismplugin->print_disclosure($cmid); + } +} +/** + * used by admin/cron.php to get similarity scores from submitted files. + * + */ +function plagiarism_cron() { + global $CFG; + if (empty($CFG->enableplagiarism)) { + return ''; + } + $plagiarismplugins = plagiarism_load_available_plugins(); + foreach($plagiarismplugins as $plugin => $dir) { + require_once($dir.'/lib.php'); + $plagiarismclass = "plagiarism_plugin_$plugin"; + $plagiarismplugin = new $plagiarismclass; + $plagiarismplugin->cron(); + } +} +/** + * helper function - also loads lib file of plagiarism plugin + * @return array of available plugins + */ +function plagiarism_load_available_plugins() { + global $CFG; + if (empty($CFG->enableplagiarism)) { + return array(); + } + $plagiarismplugins = get_plugin_list('plagiarism'); + $availableplugins = array(); + foreach($plagiarismplugins as $plugin => $dir) { + //check this plugin is enabled and a lib file exists. + if (get_config('plagiarism', $plugin."_use") && file_exists($dir."/lib.php")) { + require_once($dir.'/lib.php'); + $plagiarismclass = "plagiarism_plugin_$plugin"; + if (class_exists($plagiarismclass)) { + $availableplugins[$plugin] = $dir; + } + } + } + return $availableplugins; +} diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php index 5b5cc61cf09bb..bba8fceb20ede 100644 --- a/mod/assignment/lib.php +++ b/mod/assignment/lib.php @@ -207,6 +207,7 @@ function view_intro() { echo $OUTPUT->box_start('generalbox boxaligncenter', 'intro'); echo format_module_intro('assignment', $this->assignment, $this->cm->id); echo $OUTPUT->box_end(); + plagiarism_print_disclosure($this->cm->id); } /** @@ -1096,6 +1097,7 @@ function display_submissions($message='') { self::FILTER_REQUIRE_GRADING => get_string('requiregrading', 'assignment')); $updatepref = optional_param('updatepref', 0, PARAM_INT); + plagiarism_update_status($this->course, $this->cm); if (isset($_POST['updatepref'])){ $perpage = optional_param('perpage', 10, PARAM_INT); @@ -1873,6 +1875,8 @@ function print_user_files($userid=0, $return=false) { $button->set_format_by_file($file); $output .= $button->to_html(PORTFOLIO_ADD_ICON_LINK); } + $output .= plagiarism_get_links(array('userid'=>$userid, 'file'=>$file, 'cmid'=>$this->cm->id, 'course'=>$this->course, 'assignment'=>$this->assignment)); + $output .= '
'; } if (count($files) > 1 && $this->portfolio_exportable() && has_capability('mod/assignment:exportownsubmission', $this->context)) { $button->set_callback_options('assignment_portfolio_caller', array('id' => $this->cm->id), '/mod/assignment/locallib.php'); diff --git a/mod/assignment/renderer.php b/mod/assignment/renderer.php index 16c5f0f33a726..87282d4e1fef7 100644 --- a/mod/assignment/renderer.php +++ b/mod/assignment/renderer.php @@ -66,8 +66,9 @@ protected function htmllize_tree($tree, $dir) { foreach ($dir['files'] as $file) { $filename = $file->get_filename(); $icon = mimeinfo("icon", $filename); + $plagiarsmlinks = plagiarism_get_links(array('userid'=>$file->get_userid(), 'file'=>$file, 'cmid'=>$tree->cm->id, 'course'=>$tree->course)); $image = $this->output->pix_icon("f/$icon", $filename, 'moodle', array('class'=>'icon')); - $result .= '
  • '.$image.' '.$file->fileurl.' '.$file->portfoliobutton.'
  • '; + $result .= '
  • '.$image.' '.$file->fileurl.' '.$plagiarsmlinks.$file->portfoliobutton.'
  • '; } $result .= ''; diff --git a/mod/assignment/submissions.php b/mod/assignment/submissions.php index ee0168e4f1b82..23584656c6460 100644 --- a/mod/assignment/submissions.php +++ b/mod/assignment/submissions.php @@ -2,6 +2,7 @@ require_once("../../config.php"); require_once("lib.php"); +require_once($CFG->libdir.'/plagiarismlib.php'); $id = optional_param('id', 0, PARAM_INT); // Course module ID $a = optional_param('a', 0, PARAM_INT); // Assignment ID diff --git a/mod/assignment/type/upload/assignment.class.php b/mod/assignment/type/upload/assignment.class.php index 560265c61119d..17d84fe5061bd 100644 --- a/mod/assignment/type/upload/assignment.class.php +++ b/mod/assignment/type/upload/assignment.class.php @@ -1025,6 +1025,8 @@ function setup_elements(&$mform) { $mform->addHelpButton('var4', 'trackdrafts', 'assignment'); $mform->setDefault('var4', 1); + $course_context = get_context_instance(CONTEXT_COURSE, $COURSE->id); + plagiarism_get_form_elements_module($mform, $course_context); } function portfolio_exportable() { diff --git a/mod/assignment/type/uploadsingle/assignment.class.php b/mod/assignment/type/uploadsingle/assignment.class.php index f5b605308bb12..3183f709caa96 100644 --- a/mod/assignment/type/uploadsingle/assignment.class.php +++ b/mod/assignment/type/uploadsingle/assignment.class.php @@ -43,6 +43,8 @@ function print_student_answer($userid, $return=false){ $mimetype = $file->get_mimetype(); $path = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/mod_assignment/submission/'.$submission->id.'/'.$filename); $output .= ''.$mimetype.''.s($filename).'
    '; + $output .= plagiarism_get_links(array('userid'=>$userid, 'file'=>$file, 'cmid'=>$this->cm->id, 'course'=>$this->course, 'assignment'=>$this->assignment)); + $output .='
    '; } } } @@ -264,6 +266,9 @@ function setup_elements(&$mform) { $choices[0] = get_string('courseuploadlimit') . ' ('.display_size($COURSE->maxbytes).')'; $mform->addElement('select', 'maxbytes', get_string('maximumsize', 'assignment'), $choices); $mform->setDefault('maxbytes', $CFG->assignment_maxbytes); + + $course_context = get_context_instance(CONTEXT_COURSE, $COURSE->id); + plagiarism_get_form_elements_module($mform, $course_context); } function portfolio_exportable() { diff --git a/mod/assignment/view.php b/mod/assignment/view.php index 3985143fcde4d..2d80577189c2b 100644 --- a/mod/assignment/view.php +++ b/mod/assignment/view.php @@ -3,6 +3,7 @@ require_once("../../config.php"); require_once("lib.php"); require_once($CFG->libdir . '/completionlib.php'); +require_once($CFG->libdir . '/plagiarismlib.php'); $id = optional_param('id', 0, PARAM_INT); // Course Module ID $a = optional_param('a', 0, PARAM_INT); // Assignment ID diff --git a/plagiarism/lib.php b/plagiarism/lib.php new file mode 100644 index 0000000000000..ea58f52a20088 --- /dev/null +++ b/plagiarism/lib.php @@ -0,0 +1,76 @@ +. + +/** + * lib.php - Contains Plagiarism base class used by plugins. + * + * @since 2.0 + * @package moodlecore + * @subpackage plagiarism + * @copyright 2010 Dan Marsden http://danmarsden.com + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page +} + +//dummy class - all plugins should be based off this. +class plagiarism_plugin { + /** + * hook to allow plagiarism specific information to be displayed beside a submission + * @param array $linkarraycontains all relevant information for the plugin to generate a link + * @return string + * + */ + public function get_links($linkarray) { + return ''; + } + /** + * hook to add plagiarism specific settings to a module settings page + * @param object $mform - Moodle form + * @param object $context - current context + */ + public function get_form_elements_module($mform, $context) { + } + /* hook to save plagiarism specific settings on a module settings page + * @param object $data - data from an mform submission. + */ + public function save_form_elements($data) { + } + /** + * hook to allow a disclosure to be printed notifying users what will happen with their submission + * @param int $cmid - course module id + * @return string + */ + public function print_disclosure($cmid) { + } + /** + * hook to allow status of submitted files to be updated - called on grading/report pages. + * + * @param object $course - full Course object + * @param object $cm - full cm object + */ + public function update_status($course, $cm) { + } + /** + * hook for cron + * + */ + public function plagiarism_cron() { + } +} \ No newline at end of file