���ѧۧݧ�ӧ�� �ާ֧ߧ֧էا֧� - ���֧էѧܧ�ڧ��ӧѧ�� - /home3/cpr76684/public_html/submission.tar
���ѧ٧ѧ�
comments/db/upgrade.php 0000644 00000002655 15152704263 0011133 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Upgrade code for install * * @package assignsubmission_comments * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Stub for upgrade code * @param int $oldversion * @return bool */ function xmldb_assignsubmission_comments_upgrade($oldversion) { global $CFG; // Automatically generated Moodle v3.9.0 release upgrade line. // Put any upgrade step following this. // Automatically generated Moodle v4.0.0 release upgrade line. // Put any upgrade step following this. // Automatically generated Moodle v4.1.0 release upgrade line. // Put any upgrade step following this. return true; } comments/db/install.php 0000644 00000002713 15152704263 0011145 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Post-install code for the submission_comments module. * * @package assignsubmission_comments * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Code run after the module database tables have been created. * Moves the comments plugin to the bottom * @return bool */ function xmldb_assignsubmission_comments_install() { global $CFG; require_once($CFG->dirroot . '/mod/assign/adminlib.php'); // Set the correct initial order for the plugins. $pluginmanager = new assign_plugin_manager('assignsubmission'); $pluginmanager->move_plugin('comments', 'down'); $pluginmanager->move_plugin('comments', 'down'); return true; } comments/db/access.php 0000644 00000001663 15152704263 0010743 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Capability definitions for this module. * * @package assignsubmission_comments * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $capabilities = array( ); comments/locallib.php 0000644 00000015101 15152704263 0010666 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the definition for the library class for online comment submission plugin * * @package assignsubmission_comments * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/comment/lib.php'); require_once($CFG->dirroot . '/mod/assign/submissionplugin.php'); /** * Library class for comment submission plugin extending submission plugin base class * * @package assignsubmission_comments * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class assign_submission_comments extends assign_submission_plugin { /** * Get the name of the online comment submission plugin * @return string */ public function get_name() { return get_string('pluginname', 'assignsubmission_comments'); } /** * Display AJAX based comment in the submission status table * * @param stdClass $submission * @param bool $showviewlink - If the comments are long this is * set to true so they can be shown in a separate page * @return string */ public function view_summary(stdClass $submission, & $showviewlink) { // Never show a link to view full submission. $showviewlink = false; // Need to used this init() otherwise it does not have the javascript includes. comment::init(); $options = new stdClass(); $options->area = 'submission_comments'; $options->course = $this->assignment->get_course(); $options->context = $this->assignment->get_context(); $options->itemid = $submission->id; $options->component = 'assignsubmission_comments'; $options->showcount = true; $options->displaycancel = true; $comment = new comment($options); $o = $this->assignment->get_renderer()->container($comment->output(true), 'commentscontainer'); return $o; } /** * Always return true because the submission comments are not part of the submission form. * * @param stdClass $submission * @return bool */ public function is_empty(stdClass $submission) { return true; } /** * Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type * and version. * * @param string $type old assignment subtype * @param int $version old assignment version * @return bool True if upgrade is possible */ public function can_upgrade($type, $version) { if ($type == 'upload' && $version >= 2011112900) { return true; } return false; } /** * Upgrade the settings from the old assignment to the new plugin based one * * @param context $oldcontext - the context for the old assignment * @param stdClass $oldassignment - the data for the old assignment * @param string $log - can be appended to by the upgrade * @return bool was it a success? (false will trigger a rollback) */ public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) { if ($oldassignment->assignmenttype == 'upload') { // Disable if allow notes was not enabled. if (!$oldassignment->var2) { $this->disable(); } } return true; } /** * Upgrade the submission from the old assignment to the new one * * @param context $oldcontext The context for the old assignment * @param stdClass $oldassignment The data record for the old assignment * @param stdClass $oldsubmission The data record for the old submission * @param stdClass $submission The new submission record * @param string $log Record upgrade messages in the log * @return bool true or false - false will trigger a rollback */ public function upgrade(context $oldcontext, stdClass $oldassignment, stdClass $oldsubmission, stdClass $submission, & $log) { if ($oldsubmission->data1 != '') { // Need to used this init() otherwise it does not have the javascript includes. comment::init(); $options = new stdClass(); $options->area = 'submission_comments_upgrade'; $options->course = $this->assignment->get_course(); $options->context = $this->assignment->get_context(); $options->itemid = $submission->id; $options->component = 'assignsubmission_comments'; $options->showcount = true; $options->displaycancel = true; $comment = new comment($options); $comment->add($oldsubmission->data1); $comment->set_view_permission(true); return $comment->output(true); } return true; } /** * The submission comments plugin has no submission component so should not be counted * when determining whether to show the edit submission link. * @return boolean */ public function allow_submissions() { return false; } /** * Automatically enable or disable this plugin based on "$CFG->commentsenabled" * * @return bool */ public function is_enabled() { global $CFG; return (!empty($CFG->usecomments)); } /** * Automatically hide the setting for the submission plugin. * * @return bool */ public function is_configurable() { return false; } /** * Return the plugin configs for external functions. * * @return array the list of settings * @since Moodle 3.2 */ public function get_config_for_external() { return (array) $this->get_config(); } } comments/tests/privacy/provider_test.php 0000644 00000040003 15152704263 0014614 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Unit tests for assignsubmission_comments. * * @package assignsubmission_comments * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_comments\privacy; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/assign/tests/privacy/provider_test.php'); use mod_assign\privacy\useridlist; /** * Unit tests for mod/assign/submission/comments/classes/privacy/ * * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider_test extends \mod_assign\privacy\provider_test { /** * Convenience function for creating feedback data. * * @param object $assign assign object * @param stdClass $student user object * @param string $submissiontext Submission text * @return array Submission plugin object and the submission object and the comment object. */ protected function create_comment_submission($assign, $student, $submissiontext) { $submission = $assign->get_user_submission($student->id, true); $plugin = $assign->get_submission_plugin_by_type('comments'); $context = $assign->get_context(); $options = new \stdClass(); $options->area = 'submission_comments'; $options->course = $assign->get_course(); $options->context = $context; $options->itemid = $submission->id; $options->component = 'assignsubmission_comments'; $options->showcount = true; $options->displaycancel = true; $comment = new \comment($options); $comment->set_post_permission(true); $this->setUser($student); $comment->add($submissiontext); return [$plugin, $submission, $comment]; } /** * Quick test to make sure that get_metadata returns something. */ public function test_get_metadata() { $collection = new \core_privacy\local\metadata\collection('assignsubmission_comments'); $collection = \assignsubmission_comments\privacy\provider::get_metadata($collection); $this->assertNotEmpty($collection); } /** * Test returning the context for a user who has made a comment in an assignment. */ public function test_get_context_for_userid_within_submission() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); // Teacher. $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studentcomment = 'Comment from user 1'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment); $teachercomment = 'From the teacher'; $this->setUser($user2); $comment->add($teachercomment); $contextlist = new \core_privacy\local\request\contextlist(); \assignsubmission_comments\privacy\provider::get_context_for_userid_within_submission($user2->id, $contextlist); $this->assertEquals($context->id, $contextlist->get_contextids()[0]); } /** * Test returning student ids given a user ID. */ public function test_get_student_user_ids() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); // Teacher. $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studentcomment = 'Comment from user 1'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment); $teachercomment = 'From the teacher'; $this->setUser($user2); $comment->add($teachercomment); $useridlist = new useridlist($user2->id, $assign->get_instance()->id); \assignsubmission_comments\privacy\provider::get_student_user_ids($useridlist); $this->assertEquals($user1->id, $useridlist->get_userids()[0]->id); } /** * Test returning users related to a given context. */ public function test_get_userids_from_context() { // Get a bunch of users making comments. // Some in one context some in another. $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); // Only in first context. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); // First and second context. $user3 = $this->getDataGenerator()->create_user(); // Second context only. $user4 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $assign1 = $this->create_instance(['course' => $course]); $assign2 = $this->create_instance(['course' => $course]); $assigncontext1 = $assign1->get_context(); $assigncontext2 = $assign2->get_context(); $user1comment = 'Comment from user 1'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign1, $user1, $user1comment); $user2comment = 'From user 2'; $this->setUser($user2); $comment->add($user2comment); $user3comment = 'User 3 comment'; $this->setUser($user3); $comment->add($user3comment); $user4comment = 'Comment from user 4'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign2, $user4, $user4comment); $user3secondcomment = 'Comment on user 4 post.'; $this->setUser($user3); $comment->add($user3comment); $userlist = new \core_privacy\local\request\userlist($assigncontext1, 'assignsubmission_comments'); \assignsubmission_comments\privacy\provider::get_userids_from_context($userlist); $userids = $userlist->get_userids(); $this->assertCount(3, $userids); // User 1,2 and 3 are the expected ones in the array. User 4 isn't. $this->assertContainsEquals($user1->id, $userids); $this->assertContainsEquals($user2->id, $userids); $this->assertContainsEquals($user3->id, $userids); $this->assertNotContainsEquals($user4->id, $userids); } /** * Test that comments are exported for a user. */ public function test_export_submission_user_data() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); // Teacher. $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studentcomment = 'Comment from user 1'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment); $teachercomment = 'From the teacher'; $this->setUser($user2); $comment->add($teachercomment); $writer = \core_privacy\local\request\writer::with_context($context); $this->assertFalse($writer->has_any_data()); // The student should be able to see the teachers feedback. $exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission); \assignsubmission_comments\privacy\provider::export_submission_user_data($exportdata); $exportedcomments = $writer->get_data(['Comments']); // Can't rely on these comments coming out in order. if ($exportedcomments->comments[0]->userid == $user1->id) { $exportedstudentcomment = $exportedcomments->comments[0]->content; $exportedteachercomment = $exportedcomments->comments[1]->content; } else { $exportedstudentcomment = $exportedcomments->comments[1]->content; $exportedteachercomment = $exportedcomments->comments[0]->content; } $this->assertCount(2, $exportedcomments->comments); $this->assertStringContainsString($studentcomment, $exportedstudentcomment); $this->assertStringContainsString($teachercomment, $exportedteachercomment); } /** * Test that all comments are deleted for this context. */ public function test_delete_submission_for_context() { global $DB; $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); // Teacher. $user3 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studentcomment = 'Comment from user 1'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment); $studentcomment = 'Comment from user 2'; list($plugin2, $submission2, $comment2) = $this->create_comment_submission($assign, $user2, $studentcomment); $teachercomment1 = 'From the teacher'; $teachercomment2 = 'From the teacher for second student.'; $this->setUser($user3); $comment->add($teachercomment1); $comment2->add($teachercomment2); // Only need the context in this plugin for this operation. $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign); \assignsubmission_comments\privacy\provider::delete_submission_for_context($requestdata); $results = $DB->get_records('comments', ['contextid' => $context->id]); $this->assertEmpty($results); } /** * Test that the comments for a user are deleted. */ public function test_delete_submission_for_userid() { global $DB; $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); // Teacher. $user3 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studentcomment = 'Comment from user 1'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment); $studentcomment = 'Comment from user 2'; list($plugin2, $submission2, $comment2) = $this->create_comment_submission($assign, $user2, $studentcomment); $teachercomment1 = 'From the teacher'; $teachercomment2 = 'From the teacher for second student.'; $this->setUser($user3); $comment->add($teachercomment1); $comment2->add($teachercomment2); // Provide full details to delete the comments. $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, null, [], $user1); \assignsubmission_comments\privacy\provider::delete_submission_for_userid($requestdata); $results = $DB->get_records('comments', ['contextid' => $context->id]); // We are only deleting the comments for user1 (one comment) so we should have three left. $this->assertCount(3, $results); foreach ($results as $result) { // Check that none of the comments are from user1. $this->assertNotEquals($user1->id, $result->userid); } } /** * Test deletion of all submissions for a context works. */ public function test_delete_submissions() { global $DB; // Get a bunch of users making comments. // Some in one context some in another. $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); // Only in first context. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); // First and second context. $user3 = $this->getDataGenerator()->create_user(); // Second context only. $user4 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $assign1 = $this->create_instance(['course' => $course]); $assign2 = $this->create_instance(['course' => $course]); $assigncontext1 = $assign1->get_context(); $assigncontext2 = $assign2->get_context(); $user1comment = 'Comment from user 1'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign1, $user1, $user1comment); $user2comment = 'From user 2'; $this->setUser($user2); $comment->add($user2comment); $user3comment = 'User 3 comment'; $this->setUser($user3); $comment->add($user3comment); $user4comment = 'Comment from user 4'; list($plugin, $submission, $comment) = $this->create_comment_submission($assign2, $user4, $user4comment); $user3secondcomment = 'Comment on user 4 post.'; $this->setUser($user3); $comment->add($user3comment); // There should be three entries. One for the first three users. $results = $DB->get_records('comments', ['contextid' => $assigncontext1->id]); $this->assertCount(3, $results); $deletedata = new \mod_assign\privacy\assign_plugin_request_data($assigncontext1, $assign1); $deletedata->set_userids([$user1->id, $user3->id]); \assignsubmission_comments\privacy\provider::delete_submissions($deletedata); // We should be left with just a comment from user 2. $results = $DB->get_records('comments', ['contextid' => $assigncontext1->id]); $this->assertCount(1, $results); $this->assertEquals($user2comment, current($results)->content); } } comments/tests/event/events_test.php 0000644 00000011531 15152704263 0013736 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Events tests. * * @package assignsubmission_comments * @category test * @copyright 2013 Rajesh Taneja <rajesh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_comments\event; use mod_assign_test_generator; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/assign/lib.php'); require_once($CFG->dirroot . '/mod/assign/locallib.php'); require_once($CFG->dirroot . '/mod/assign/tests/generator.php'); require_once($CFG->dirroot . '/comment/lib.php'); /** * Events tests class. * * @package assignsubmission_comments * @category test * @copyright 2013 Rajesh Taneja <rajesh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class events_test extends \advanced_testcase { // Use the generator helper. use mod_assign_test_generator; /** * Test comment_created event. */ public function test_comment_created() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course); $this->setUser($teacher); $submission = $assign->get_user_submission($student->id, true); $context = $assign->get_context(); $options = new \stdClass(); $options->area = 'submission_comments'; $options->course = $assign->get_course(); $options->context = $context; $options->itemid = $submission->id; $options->component = 'assignsubmission_comments'; $options->showcount = true; $options->displaycancel = true; $comment = new \comment($options); // Triggering and capturing the event. $sink = $this->redirectEvents(); $comment->add('New comment'); $events = $sink->get_events(); $this->assertCount(1, $events); $event = reset($events); $sink->close(); // Checking that the event contains the expected values. $this->assertInstanceOf('\assignsubmission_comments\event\comment_created', $event); $this->assertEquals($context, $event->get_context()); $url = new \moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)); $this->assertEquals($url, $event->get_url()); $this->assertEventContextNotUsed($event); } /** * Test comment_deleted event. */ public function test_comment_deleted() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course); $this->setUser($teacher); $submission = $assign->get_user_submission($student->id, true); $context = $assign->get_context(); $options = new \stdClass(); $options->area = 'submission_comments'; $options->course = $assign->get_course(); $options->context = $context; $options->itemid = $submission->id; $options->component = 'assignsubmission_comments'; $options->showcount = true; $options->displaycancel = true; $comment = new \comment($options); $newcomment = $comment->add('New comment 1'); // Triggering and capturing the event. $sink = $this->redirectEvents(); $comment->delete($newcomment->id); $events = $sink->get_events(); $this->assertCount(1, $events); $event = reset($events); // Checking that the event contains the expected values. $this->assertInstanceOf('\assignsubmission_comments\event\comment_deleted', $event); $this->assertEquals($context, $event->get_context()); $url = new \moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)); $this->assertEquals($url, $event->get_url()); $this->assertEventContextNotUsed($event); } } comments/lib.php 0000644 00000020122 15152704263 0007652 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the moodle hooks for the submission comments plugin * * @package assignsubmission_comments * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * * Callback method for data validation---- required method for AJAXmoodle based comment API * * @param stdClass $options * @return bool */ function assignsubmission_comments_comment_validate(stdClass $options) { global $USER, $CFG, $DB; if ($options->commentarea != 'submission_comments' && $options->commentarea != 'submission_comments_upgrade') { throw new comment_exception('invalidcommentarea'); } if (!$submission = $DB->get_record('assign_submission', array('id'=>$options->itemid))) { throw new comment_exception('invalidcommentitemid'); } $context = $options->context; require_once($CFG->dirroot . '/mod/assign/locallib.php'); static $assignment = null; if (is_null($assignment) || $assignment->get_context() != $context) { $assignment = new assign($context, null, null); } if ($assignment->get_instance()->id != $submission->assignment) { throw new comment_exception('invalidcontext'); } return true; } /** * Permission control method for submission plugin ---- required method for AJAXmoodle based comment API * * @param stdClass $options * @return array */ function assignsubmission_comments_comment_permissions(stdClass $options) { global $USER, $CFG, $DB; if ($options->commentarea != 'submission_comments' && $options->commentarea != 'submission_comments_upgrade') { throw new comment_exception('invalidcommentarea'); } if (!$submission = $DB->get_record('assign_submission', array('id'=>$options->itemid))) { throw new comment_exception('invalidcommentitemid'); } $context = $options->context; require_once($CFG->dirroot . '/mod/assign/locallib.php'); static $assignment = null; if (is_null($assignment) || $assignment->get_context() != $context) { $assignment = new assign($context, null, null); } if ($assignment->get_instance()->id != $submission->assignment) { throw new comment_exception('invalidcontext'); } if ($assignment->get_instance()->teamsubmission && !$assignment->can_view_group_submission($submission->groupid)) { return array('post' => false, 'view' => false); } if (!$assignment->get_instance()->teamsubmission && !$assignment->can_view_submission($submission->userid)) { return array('post' => false, 'view' => false); } return array('post' => true, 'view' => true); } /** * Callback called by comment::get_comments() and comment::add(). Gives an opportunity to enforce blind-marking. * * @param array $comments * @param stdClass $options * @return array * @throws comment_exception */ function assignsubmission_comments_comment_display($comments, $options) { global $CFG, $DB, $USER; if ($options->commentarea != 'submission_comments' && $options->commentarea != 'submission_comments_upgrade') { throw new comment_exception('invalidcommentarea'); } if (!$submission = $DB->get_record('assign_submission', array('id'=>$options->itemid))) { throw new comment_exception('invalidcommentitemid'); } $context = $options->context; $cm = $options->cm; $course = $options->courseid; require_once($CFG->dirroot . '/mod/assign/locallib.php'); $assignment = new assign($context, $cm, $course); if ($assignment->get_instance()->id != $submission->assignment) { throw new comment_exception('invalidcontext'); } if ($assignment->is_blind_marking() && !empty($comments)) { // Blind marking is being used, may need to map unique anonymous ids to the comments. $usermappings = array(); $guestuser = guest_user(); // Check group users first. $userinteam = false; if ($assignment->get_instance()->teamsubmission && has_capability('mod/assign:submit', $context)) { $assignment->set_course(get_course($course)); $userinteam = $assignment->can_edit_group_submission($submission->groupid); } foreach ($comments as $comment) { if (has_capability('mod/assign:viewblinddetails', $context) && $USER->id != $comment->userid) { $anonid = $assignment->get_uniqueid_for_user($comment->userid); // Show participant information and the user's full name to users with the view blind details capability. $a = new stdClass(); $a->participantnumber = $anonid; $a->participantfullname = $comment->fullname; $comment->fullname = get_string('blindmarkingviewfullname', 'assignsubmission_comments', $a); } else if ($USER->id == $comment->userid || $submission->userid == $USER->id || $userinteam) { // phpcs:ignore // Do not anonymize the user details for this comment. } else { // Anonymize the comments. if (empty($usermappings[$comment->userid])) { $anonid = $assignment->get_uniqueid_for_user($comment->userid); // The blind-marking information for this commenter has not been generated; do so now. $commenter = new stdClass(); $commenter->firstname = get_string('blindmarkingname', 'assignsubmission_comments', $anonid); $commenter->lastname = ''; $commenter->firstnamephonetic = ''; $commenter->lastnamephonetic = ''; $commenter->middlename = ''; $commenter->alternatename = ''; $commenter->picture = 0; $commenter->id = $guestuser->id; $commenter->email = $guestuser->email; $commenter->imagealt = $guestuser->imagealt; // Temporarily store blind-marking information for use in later comments if necessary. $usermappings[$comment->userid] = new stdClass(); $usermappings[$comment->userid]->fullname = fullname($commenter); $usermappings[$comment->userid]->avatar = $assignment->get_renderer()->user_picture($commenter, array('size' => 18, 'link' => false)); } // Set blind-marking information for this comment. $comment->fullname = $usermappings[$comment->userid]->fullname; $comment->avatar = $usermappings[$comment->userid]->avatar; $comment->profileurl = null; } } } return $comments; } /** * Callback to force the userid for all comments to be the userid of the submission and NOT the global $USER->id. This * is required by the upgrade code. Note the comment area is used to identify upgrades. * * @param stdClass $comment * @param stdClass $param */ function assignsubmission_comments_comment_add(stdClass $comment, stdClass $param) { global $DB; if ($comment->commentarea == 'submission_comments_upgrade') { $submissionid = $comment->itemid; $submission = $DB->get_record('assign_submission', array('id' => $submissionid)); $comment->userid = $submission->userid; $comment->commentarea = 'submission_comments'; } } comments/version.php 0000644 00000002127 15152704263 0010576 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the version information for the comments submission plugin * * @package assignsubmission_comments * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $plugin->version = 2022112800; $plugin->requires = 2022111800; $plugin->component = 'assignsubmission_comments'; comments/classes/privacy/provider.php 0000644 00000016230 15152704263 0014055 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Privacy class for requesting user data. * * @package assignsubmission_comments * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_comments\privacy; defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/mod/assign/locallib.php'); use \core_privacy\local\metadata\collection; use \core_privacy\local\metadata\provider as metadataprovider; use \core_comment\privacy\provider as comments_provider; use \core_privacy\local\request\contextlist; use \mod_assign\privacy\assign_plugin_request_data; /** * Privacy class for requesting user data. * * @package assignsubmission_comments * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements metadataprovider, \mod_assign\privacy\assignsubmission_provider, \mod_assign\privacy\assignsubmission_user_provider { /** * Return meta data about this plugin. * * @param collection $collection A list of information to add to. * @return collection Return the collection after adding to it. */ public static function get_metadata(collection $collection) : collection { $collection->link_subsystem('core_comment', 'privacy:metadata:commentpurpose'); return $collection; } /** * It is possible to make a comment as a teacher without creating an entry in the submission table, so this is required * to find those entries. * * @param int $userid The user ID that we are finding contexts for. * @param contextlist $contextlist A context list to add sql and params to for contexts. */ public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) { $sql = "SELECT contextid FROM {comments} WHERE component = :component AND commentarea = :commentarea AND userid = :userid"; $params = ['userid' => $userid, 'component' => 'assignsubmission_comments', 'commentarea' => 'submission_comments']; $contextlist->add_from_sql($sql, $params); } /** * Due to the fact that we can't rely on the queries in the mod_assign provider we have to add some additional sql. * * @param \mod_assign\privacy\useridlist $useridlist An object for obtaining user IDs of students. */ public static function get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) { $params = ['assignid' => $useridlist->get_assignid(), 'commentuserid' => $useridlist->get_teacherid(), 'commentuserid2' => $useridlist->get_teacherid()]; $sql = "SELECT DISTINCT c.userid AS id FROM {comments} c JOIN (SELECT c.itemid FROM {comments} c JOIN {assign_submission} s ON s.id = c.itemid AND s.assignment = :assignid WHERE c.userid = :commentuserid) aa ON aa.itemid = c.itemid WHERE c.userid NOT IN (:commentuserid2)"; $useridlist->add_from_sql($sql, $params); } /** * If you have tables that contain userids and you can generate entries in your tables without creating an * entry in the assign_submission table then please fill in this method. * * @param \core_privacy\local\request\userlist $userlist The userlist object */ public static function get_userids_from_context(\core_privacy\local\request\userlist $userlist) { $context = $userlist->get_context(); if ($context->contextlevel != CONTEXT_MODULE) { return; } comments_provider::get_users_in_context_from_sql($userlist, 'c', 'assignsubmission_comments', 'submission_comments', $context->id); } /** * Export all user data for this plugin. * * @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful * information to help with exporting. */ public static function export_submission_user_data(assign_plugin_request_data $exportdata) { $component = 'assignsubmission_comments'; $commentarea = 'submission_comments'; $userid = ($exportdata->get_user() != null); $submission = $exportdata->get_pluginobject(); // For the moment we are only showing the comments made by this user. comments_provider::export_comments($exportdata->get_context(), $component, $commentarea, $submission->id, $exportdata->get_subcontext(), $userid); } /** * Delete all the comments made for this context. * * @param assign_plugin_request_data $requestdata Data to fulfill the deletion request. */ public static function delete_submission_for_context(assign_plugin_request_data $requestdata) { comments_provider::delete_comments_for_all_users($requestdata->get_context(), 'assignsubmission_comments', 'submission_comments'); } /** * A call to this method should delete user data (where practical) using the userid and submission. * * @param assign_plugin_request_data $exportdata Details about the user and context to focus the deletion. */ public static function delete_submission_for_userid(assign_plugin_request_data $exportdata) { // Create an approved context list to delete the comments. $contextlist = new \core_privacy\local\request\approved_contextlist($exportdata->get_user(), 'assignsubmission_comments', [$exportdata->get_context()->id]); comments_provider::delete_comments_for_user($contextlist, 'assignsubmission_comments', 'submission_comments'); } /** * Deletes all submissions for the submission ids / userids provided in a context. * assign_plugin_request_data contains: * - context * - assign object * - submission ids (pluginids) * - user ids * @param assign_plugin_request_data $deletedata A class that contains the relevant information required for deletion. */ public static function delete_submissions(assign_plugin_request_data $deletedata) { $userlist = new \core_privacy\local\request\approved_userlist($deletedata->get_context(), 'assignsubmission_comments', $deletedata->get_userids()); comments_provider::delete_comments_for_users($userlist, 'assignsubmission_comments', 'submission_comments'); } } comments/classes/event/comment_deleted.php 0000644 00000003606 15152704263 0015022 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * The assignsubmission_comments comment deleted event. * * @package assignsubmission_comments * @copyright 2013 Rajesh Taneja <rajesh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_comments\event; defined('MOODLE_INTERNAL') || die(); /** * The assignsubmission_comments comment deleted event. * * @package assignsubmission_comments * @since Moodle 2.7 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class comment_deleted extends \core\event\comment_deleted { /** * Get URL related to the action. * * @return \moodle_url */ public function get_url() { return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid)); } /** * Returns description of what happened. * * @return string */ public function get_description() { return "The user with id '$this->userid' deleted the comment with id '$this->objectid' from the submission " . "with id '{$this->other['itemid']}' for the assignment with course module id '$this->contextinstanceid'."; } } comments/classes/event/comment_created.php 0000644 00000003610 15152704263 0015016 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * The assignsubmission_comments comment created event. * * @package assignsubmission_comments * @copyright 2013 Rajesh Taneja <rajesh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_comments\event; defined('MOODLE_INTERNAL') || die(); /** * The assignsubmission_comments comment created event class. * * @package assignsubmission_comments * @since Moodle 2.7 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class comment_created extends \core\event\comment_created { /** * Get URL related to the action. * * @return \moodle_url */ public function get_url() { return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid)); } /** * Returns description of what happened. * * @return string */ public function get_description() { return "The user with id '$this->userid' added the comment with id '$this->objectid' to the submission " . "with id '{$this->other['itemid']}' for the assignment with course module id '$this->contextinstanceid'."; } } comments/lang/en/assignsubmission_comments.php 0000644 00000003167 15152704263 0015746 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Strings for component 'submission_comments', language 'en' * * @package assignsubmission_comments * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $string['blindmarkingname'] = 'Participant {$a}'; $string['blindmarkingviewfullname'] = 'Participant {$a->participantnumber} ({$a->participantfullname})'; $string['privacy:metadata:commentpurpose'] = 'Comments between the student and teacher about a submission.'; $string['default'] = 'Enabled by default'; $string['default_help'] = 'If set, this submission method will be enabled by default for all new assignments.'; $string['enabled'] = 'Submission comments'; $string['enabled_help'] = 'If enabled, students can leave comments on their own submission. For example, this can be used for students to specify which is the master file when submitting inter-linked files.'; $string['pluginname'] = 'Submission comments'; file/db/upgrade.php 0000644 00000002645 15152704263 0010224 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Upgrade code for install * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Stub for upgrade code * @param int $oldversion * @return bool */ function xmldb_assignsubmission_file_upgrade($oldversion) { global $CFG; // Automatically generated Moodle v3.9.0 release upgrade line. // Put any upgrade step following this. // Automatically generated Moodle v4.0.0 release upgrade line. // Put any upgrade step following this. // Automatically generated Moodle v4.1.0 release upgrade line. // Put any upgrade step following this. return true; } file/db/access.php 0000644 00000001656 15152704263 0010037 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Capability definitions for this module. * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $capabilities = array( ); file/db/install.xml 0000644 00000002530 15152704263 0010245 0 ustar 00 <?xml version="1.0" encoding="UTF-8" ?> <XMLDB PATH="mod/assign/submission/file/db" VERSION="20120423" COMMENT="XMLDB file for Moodle mod/assign/submission/file" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/xmldb/xmldb.xsd" > <TABLES> <TABLE NAME="assignsubmission_file" COMMENT="Info about file submissions for assignments"> <FIELDS> <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/> <FIELD NAME="assignment" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> <FIELD NAME="submission" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> <FIELD NAME="numfiles" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The number of files the student submitted."/> </FIELDS> <KEYS> <KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="The unique id for this submission info."/> <KEY NAME="assignment" TYPE="foreign" FIELDS="assignment" REFTABLE="assign" REFFIELDS="id" COMMENT="The assignment instance this submission relates to"/> <KEY NAME="submission" TYPE="foreign" FIELDS="submission" REFTABLE="assign_submission" REFFIELDS="id" COMMENT="The submission this file submission relates to."/> </KEYS> </TABLE> </TABLES> </XMLDB> file/locallib.php 0000644 00000061720 15152704263 0007770 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the definition for the library class for file submission plugin * * This class provides all the functionality for the new assign module. * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); // File areas for file submission assignment. define('ASSIGNSUBMISSION_FILE_MAXSUMMARYFILES', 5); define('ASSIGNSUBMISSION_FILE_FILEAREA', 'submission_files'); /** * Library class for file submission plugin extending submission plugin base class * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class assign_submission_file extends assign_submission_plugin { /** * Get the name of the file submission plugin * @return string */ public function get_name() { return get_string('file', 'assignsubmission_file'); } /** * Get file submission information from the database * * @param int $submissionid * @return mixed */ private function get_file_submission($submissionid) { global $DB; return $DB->get_record('assignsubmission_file', array('submission'=>$submissionid)); } /** * Get the default setting for file submission plugin * * @param MoodleQuickForm $mform The form to add elements to * @return void */ public function get_settings(MoodleQuickForm $mform) { global $CFG, $COURSE; if ($this->assignment->has_instance()) { $defaultmaxfilesubmissions = $this->get_config('maxfilesubmissions'); $defaultmaxsubmissionsizebytes = $this->get_config('maxsubmissionsizebytes'); $defaultfiletypes = $this->get_config('filetypeslist'); } else { $defaultmaxfilesubmissions = get_config('assignsubmission_file', 'maxfiles'); $defaultmaxsubmissionsizebytes = get_config('assignsubmission_file', 'maxbytes'); $defaultfiletypes = get_config('assignsubmission_file', 'filetypes'); } $defaultfiletypes = (string)$defaultfiletypes; $settings = array(); $options = array(); for ($i = 1; $i <= get_config('assignsubmission_file', 'maxfiles'); $i++) { $options[$i] = $i; } $name = get_string('maxfilessubmission', 'assignsubmission_file'); $mform->addElement('select', 'assignsubmission_file_maxfiles', $name, $options); $mform->addHelpButton('assignsubmission_file_maxfiles', 'maxfilessubmission', 'assignsubmission_file'); $mform->setDefault('assignsubmission_file_maxfiles', $defaultmaxfilesubmissions); $mform->hideIf('assignsubmission_file_maxfiles', 'assignsubmission_file_enabled', 'notchecked'); $choices = get_max_upload_sizes($CFG->maxbytes, $COURSE->maxbytes, get_config('assignsubmission_file', 'maxbytes')); $settings[] = array('type' => 'select', 'name' => 'maxsubmissionsizebytes', 'description' => get_string('maximumsubmissionsize', 'assignsubmission_file'), 'options'=> $choices, 'default'=> $defaultmaxsubmissionsizebytes); $name = get_string('maximumsubmissionsize', 'assignsubmission_file'); $mform->addElement('select', 'assignsubmission_file_maxsizebytes', $name, $choices); $mform->addHelpButton('assignsubmission_file_maxsizebytes', 'maximumsubmissionsize', 'assignsubmission_file'); $mform->setDefault('assignsubmission_file_maxsizebytes', $defaultmaxsubmissionsizebytes); $mform->hideIf('assignsubmission_file_maxsizebytes', 'assignsubmission_file_enabled', 'notchecked'); $name = get_string('acceptedfiletypes', 'assignsubmission_file'); $mform->addElement('filetypes', 'assignsubmission_file_filetypes', $name); $mform->addHelpButton('assignsubmission_file_filetypes', 'acceptedfiletypes', 'assignsubmission_file'); $mform->setDefault('assignsubmission_file_filetypes', $defaultfiletypes); $mform->hideIf('assignsubmission_file_filetypes', 'assignsubmission_file_enabled', 'notchecked'); } /** * Save the settings for file submission plugin * * @param stdClass $data * @return bool */ public function save_settings(stdClass $data) { $this->set_config('maxfilesubmissions', $data->assignsubmission_file_maxfiles); $this->set_config('maxsubmissionsizebytes', $data->assignsubmission_file_maxsizebytes); if (!empty($data->assignsubmission_file_filetypes)) { $this->set_config('filetypeslist', $data->assignsubmission_file_filetypes); } else { $this->set_config('filetypeslist', ''); } return true; } /** * File format options * * @return array */ private function get_file_options() { $fileoptions = array('subdirs' => 1, 'maxbytes' => $this->get_config('maxsubmissionsizebytes'), 'maxfiles' => $this->get_config('maxfilesubmissions'), 'accepted_types' => $this->get_configured_typesets(), 'return_types' => (FILE_INTERNAL | FILE_CONTROLLED_LINK)); if ($fileoptions['maxbytes'] == 0) { // Use module default. $fileoptions['maxbytes'] = get_config('assignsubmission_file', 'maxbytes'); } return $fileoptions; } /** * Add elements to submission form * * @param mixed $submission stdClass|null * @param MoodleQuickForm $mform * @param stdClass $data * @return bool */ public function get_form_elements($submission, MoodleQuickForm $mform, stdClass $data) { global $OUTPUT; if ($this->get_config('maxfilesubmissions') <= 0) { return false; } $fileoptions = $this->get_file_options(); $submissionid = $submission ? $submission->id : 0; $data = file_prepare_standard_filemanager($data, 'files', $fileoptions, $this->assignment->get_context(), 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submissionid); $mform->addElement('filemanager', 'files_filemanager', $this->get_name(), null, $fileoptions); return true; } /** * Count the number of files * * @param int $submissionid * @param string $area * @return int */ private function count_files($submissionid, $area) { $fs = get_file_storage(); $files = $fs->get_area_files($this->assignment->get_context()->id, 'assignsubmission_file', $area, $submissionid, 'id', false); return count($files); } /** * Save the files and trigger plagiarism plugin, if enabled, * to scan the uploaded files via events trigger * * @param stdClass $submission * @param stdClass $data * @return bool */ public function save(stdClass $submission, stdClass $data) { global $USER, $DB; $fileoptions = $this->get_file_options(); $data = file_postupdate_standard_filemanager($data, 'files', $fileoptions, $this->assignment->get_context(), 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id); $filesubmission = $this->get_file_submission($submission->id); // Plagiarism code event trigger when files are uploaded. $fs = get_file_storage(); $files = $fs->get_area_files($this->assignment->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id, 'id', false); $count = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA); $params = array( 'context' => context_module::instance($this->assignment->get_course_module()->id), 'courseid' => $this->assignment->get_course()->id, 'objectid' => $submission->id, 'other' => array( 'content' => '', 'pathnamehashes' => array_keys($files) ) ); if (!empty($submission->userid) && ($submission->userid != $USER->id)) { $params['relateduserid'] = $submission->userid; } if ($this->assignment->is_blind_marking()) { $params['anonymous'] = 1; } $event = \assignsubmission_file\event\assessable_uploaded::create($params); $event->set_legacy_files($files); $event->trigger(); $groupname = null; $groupid = 0; // Get the group name as other fields are not transcribed in the logs and this information is important. if (empty($submission->userid) && !empty($submission->groupid)) { $groupname = $DB->get_field('groups', 'name', array('id' => $submission->groupid), MUST_EXIST); $groupid = $submission->groupid; } else { $params['relateduserid'] = $submission->userid; } // Unset the objectid and other field from params for use in submission events. unset($params['objectid']); unset($params['other']); $params['other'] = array( 'submissionid' => $submission->id, 'submissionattempt' => $submission->attemptnumber, 'submissionstatus' => $submission->status, 'filesubmissioncount' => $count, 'groupid' => $groupid, 'groupname' => $groupname ); if ($filesubmission) { $filesubmission->numfiles = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA); $updatestatus = $DB->update_record('assignsubmission_file', $filesubmission); $params['objectid'] = $filesubmission->id; $event = \assignsubmission_file\event\submission_updated::create($params); $event->set_assign($this->assignment); $event->trigger(); return $updatestatus; } else { $filesubmission = new stdClass(); $filesubmission->numfiles = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA); $filesubmission->submission = $submission->id; $filesubmission->assignment = $this->assignment->get_instance()->id; $filesubmission->id = $DB->insert_record('assignsubmission_file', $filesubmission); $params['objectid'] = $filesubmission->id; $event = \assignsubmission_file\event\submission_created::create($params); $event->set_assign($this->assignment); $event->trigger(); return $filesubmission->id > 0; } } /** * Remove files from this submission. * * @param stdClass $submission The submission * @return boolean */ public function remove(stdClass $submission) { global $DB; $fs = get_file_storage(); $fs->delete_area_files($this->assignment->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id); $currentsubmission = $this->get_file_submission($submission->id); if ($currentsubmission) { $currentsubmission->numfiles = 0; $DB->update_record('assignsubmission_file', $currentsubmission); } return true; } /** * Produce a list of files suitable for export that represent this feedback or submission * * @param stdClass $submission The submission * @param stdClass $user The user record - unused * @return array - return an array of files indexed by filename */ public function get_files(stdClass $submission, stdClass $user) { $result = array(); $fs = get_file_storage(); $files = $fs->get_area_files($this->assignment->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id, 'timemodified', false); foreach ($files as $file) { // Do we return the full folder path or just the file name? if (isset($submission->exportfullpath) && $submission->exportfullpath == false) { $result[$file->get_filename()] = $file; } else { $result[$file->get_filepath().$file->get_filename()] = $file; } } return $result; } /** * Display the list of files in the submission status table * * @param stdClass $submission * @param bool $showviewlink Set this to true if the list of files is long * @return string */ public function view_summary(stdClass $submission, & $showviewlink) { $count = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA); // Show we show a link to view all files for this plugin? $showviewlink = $count > ASSIGNSUBMISSION_FILE_MAXSUMMARYFILES; if ($count <= ASSIGNSUBMISSION_FILE_MAXSUMMARYFILES) { return $this->assignment->render_area_files('assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id); } else { return get_string('countfiles', 'assignsubmission_file', $count); } } /** * No full submission view - the summary contains the list of files and that is the whole submission * * @param stdClass $submission * @return string */ public function view(stdClass $submission) { return $this->assignment->render_area_files('assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id); } /** * Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type * and version. * * @param string $type * @param int $version * @return bool True if upgrade is possible */ public function can_upgrade($type, $version) { $uploadsingletype ='uploadsingle'; $uploadtype ='upload'; if (($type == $uploadsingletype || $type == $uploadtype) && $version >= 2011112900) { return true; } return false; } /** * Upgrade the settings from the old assignment * to the new plugin based one * * @param context $oldcontext - the old assignment context * @param stdClass $oldassignment - the old assignment data record * @param string $log record log events here * @return bool Was it a success? (false will trigger rollback) */ public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) { global $DB; if ($oldassignment->assignmenttype == 'uploadsingle') { $this->set_config('maxfilesubmissions', 1); $this->set_config('maxsubmissionsizebytes', $oldassignment->maxbytes); return true; } else if ($oldassignment->assignmenttype == 'upload') { $this->set_config('maxfilesubmissions', $oldassignment->var1); $this->set_config('maxsubmissionsizebytes', $oldassignment->maxbytes); // Advanced file upload uses a different setting to do the same thing. $DB->set_field('assign', 'submissiondrafts', $oldassignment->var4, array('id'=>$this->assignment->get_instance()->id)); // Convert advanced file upload "hide description before due date" setting. $alwaysshow = 0; if (!$oldassignment->var3) { $alwaysshow = 1; } $DB->set_field('assign', 'alwaysshowdescription', $alwaysshow, array('id'=>$this->assignment->get_instance()->id)); return true; } } /** * Upgrade the submission from the old assignment to the new one * * @param context $oldcontext The context of the old assignment * @param stdClass $oldassignment The data record for the old oldassignment * @param stdClass $oldsubmission The data record for the old submission * @param stdClass $submission The data record for the new submission * @param string $log Record upgrade messages in the log * @return bool true or false - false will trigger a rollback */ public function upgrade(context $oldcontext, stdClass $oldassignment, stdClass $oldsubmission, stdClass $submission, & $log) { global $DB; $filesubmission = new stdClass(); $filesubmission->numfiles = $oldsubmission->numfiles; $filesubmission->submission = $submission->id; $filesubmission->assignment = $this->assignment->get_instance()->id; if (!$DB->insert_record('assignsubmission_file', $filesubmission) > 0) { $log .= get_string('couldnotconvertsubmission', 'mod_assign', $submission->userid); return false; } // Now copy the area files. $this->assignment->copy_area_files_for_upgrade($oldcontext->id, 'mod_assignment', 'submission', $oldsubmission->id, $this->assignment->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id); return true; } /** * The assignment has been deleted - cleanup * * @return bool */ public function delete_instance() { global $DB; // Will throw exception on failure. $DB->delete_records('assignsubmission_file', array('assignment'=>$this->assignment->get_instance()->id)); return true; } /** * Formatting for log info * * @param stdClass $submission The submission * @return string */ public function format_for_log(stdClass $submission) { // Format the info for each submission plugin (will be added to log). $filecount = $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA); return get_string('numfilesforlog', 'assignsubmission_file', $filecount); } /** * Return true if there are no submission files * @param stdClass $submission */ public function is_empty(stdClass $submission) { return $this->count_files($submission->id, ASSIGNSUBMISSION_FILE_FILEAREA) == 0; } /** * Determine if a submission is empty * * This is distinct from is_empty in that it is intended to be used to * determine if a submission made before saving is empty. * * @param stdClass $data The submission data * @return bool */ public function submission_is_empty(stdClass $data) { global $USER; $fs = get_file_storage(); // Get a count of all the draft files, excluding any directories. $files = $fs->get_area_files(context_user::instance($USER->id)->id, 'user', 'draft', $data->files_filemanager, 'id', false); return count($files) == 0; } /** * Get file areas returns a list of areas this plugin stores files * @return array - An array of fileareas (keys) and descriptions (values) */ public function get_file_areas() { return array(ASSIGNSUBMISSION_FILE_FILEAREA=>$this->get_name()); } /** * Copy the student's submission from a previous submission. Used when a student opts to base their resubmission * on the last submission. * @param stdClass $sourcesubmission * @param stdClass $destsubmission */ public function copy_submission(stdClass $sourcesubmission, stdClass $destsubmission) { global $DB; // Copy the files across. $contextid = $this->assignment->get_context()->id; $fs = get_file_storage(); $files = $fs->get_area_files($contextid, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $sourcesubmission->id, 'id', false); foreach ($files as $file) { $fieldupdates = array('itemid' => $destsubmission->id); $fs->create_file_from_storedfile($fieldupdates, $file); } // Copy the assignsubmission_file record. if ($filesubmission = $this->get_file_submission($sourcesubmission->id)) { unset($filesubmission->id); $filesubmission->submission = $destsubmission->id; $DB->insert_record('assignsubmission_file', $filesubmission); } return true; } /** * Return a description of external params suitable for uploading a file submission from a webservice. * * @return external_description|null */ public function get_external_parameters() { return array( 'files_filemanager' => new external_value( PARAM_INT, 'The id of a draft area containing files for this submission.', VALUE_OPTIONAL ) ); } /** * Return the plugin configs for external functions. * * @return array the list of settings * @since Moodle 3.2 */ public function get_config_for_external() { global $CFG; $configs = $this->get_config(); // Get a size in bytes. if ($configs->maxsubmissionsizebytes == 0) { $configs->maxsubmissionsizebytes = get_max_upload_file_size($CFG->maxbytes, $this->assignment->get_course()->maxbytes, get_config('assignsubmission_file', 'maxbytes')); } return (array) $configs; } /** * Get the type sets configured for this assignment. * * @return array('groupname', 'mime/type', ...) */ private function get_configured_typesets() { $typeslist = (string)$this->get_config('filetypeslist'); $util = new \core_form\filetypes_util(); $sets = $util->normalize_file_types($typeslist); return $sets; } /** * Determine if the plugin allows image file conversion * @return bool */ public function allow_image_conversion() { return true; } } file/tests/privacy/provider_test.php 0000644 00000025443 15152704263 0013721 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Unit tests for assignsubmission_file. * * @package assignsubmission_file * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_file\privacy; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/assign/tests/privacy/provider_test.php'); /** * Unit tests for mod/assign/submission/file/classes/privacy/ * * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider_test extends \mod_assign\privacy\provider_test { /** * Convenience function for creating feedback data. * * @param object $assign assign object * @param stdClass $student user object * @param string $filename filename for the file submission * @return array Submission plugin object and the submission object. */ protected function create_file_submission($assign, $student, $filename) { global $CFG; // Create a file submission with the test pdf. $submission = $assign->get_user_submission($student->id, true); $this->setUser($student->id); $fs = get_file_storage(); $pdfsubmission = (object) array( 'contextid' => $assign->get_context()->id, 'component' => 'assignsubmission_file', 'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA, 'itemid' => $submission->id, 'filepath' => '/', 'filename' => $filename ); $sourcefile = $CFG->dirroot.'/mod/assign/feedback/editpdf/tests/fixtures/submission.pdf'; $fi = $fs->create_file_from_pathname($pdfsubmission, $sourcefile); $data = new \stdClass(); $plugin = $assign->get_submission_plugin_by_type('file'); $plugin->save($submission, $data); return [$plugin, $submission]; } /** * Quick test to make sure that get_metadata returns something. */ public function test_get_metadata() { $collection = new \core_privacy\local\metadata\collection('assignsubmission_file'); $collection = \assignsubmission_file\privacy\provider::get_metadata($collection); $this->assertNotEmpty($collection); } /** * Test that submission files are exported for a user. */ public function test_export_submission_user_data() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); // Teacher. $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studentfilename = 'user1file.pdf'; list($plugin, $submission) = $this->create_file_submission($assign, $user1, $studentfilename); $writer = \core_privacy\local\request\writer::with_context($context); $this->assertFalse($writer->has_any_data()); // The student should have a file submission. $exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission, ['Attempt 1']); \assignsubmission_file\privacy\provider::export_submission_user_data($exportdata); // print_object($writer); $storedfile = $writer->get_files(['Attempt 1'])['user1file.pdf']; $this->assertInstanceOf('stored_file', $storedfile); $this->assertEquals($studentfilename, $storedfile->get_filename()); } /** * Test that all submission files are deleted for this context. */ public function test_delete_submission_for_context() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studentfilename = 'user1file.pdf'; list($plugin, $submission) = $this->create_file_submission($assign, $user1, $studentfilename); $student2filename = 'user2file.pdf'; list($plugin2, $submission2) = $this->create_file_submission($assign, $user2, $studentfilename); // Only need the context and assign object in this plugin for this operation. $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign); \assignsubmission_file\privacy\provider::delete_submission_for_context($requestdata); // This checks that there are no files in this submission. $this->assertTrue($plugin->is_empty($submission)); $this->assertTrue($plugin2->is_empty($submission2)); } /** * Test that the comments for a user are deleted. */ public function test_delete_submission_for_userid() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studentfilename = 'user1file.pdf'; list($plugin, $submission) = $this->create_file_submission($assign, $user1, $studentfilename); $student2filename = 'user2file.pdf'; list($plugin2, $submission2) = $this->create_file_submission($assign, $user2, $studentfilename); // Only need the context and assign object in this plugin for this operation. $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission, [], $user1); \assignsubmission_file\privacy\provider::delete_submission_for_userid($requestdata); // This checks that there are no files in this submission. $this->assertTrue($plugin->is_empty($submission)); // There should be files here. $this->assertFalse($plugin2->is_empty($submission2)); } /** * Test deletion of bulk submissions for a context. */ public function test_delete_submissions() { global $DB; $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $user3 = $this->getDataGenerator()->create_user(); $user4 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user4->id, $course->id, 'student'); $assign1 = $this->create_instance(['course' => $course]); $assign2 = $this->create_instance(['course' => $course]); $context1 = $assign1->get_context(); $context2 = $assign2->get_context(); $student1filename = 'user1file.pdf'; list($plugin1, $submission1) = $this->create_file_submission($assign1, $user1, $student1filename); $student2filename = 'user2file.pdf'; list($plugin2, $submission2) = $this->create_file_submission($assign1, $user2, $student2filename); $student3filename = 'user3file.pdf'; list($plugin3, $submission3) = $this->create_file_submission($assign1, $user3, $student3filename); $student4filename = 'user4file.pdf'; list($plugin4, $submission4) = $this->create_file_submission($assign2, $user4, $student4filename); $student5filename = 'user5file.pdf'; list($plugin5, $submission5) = $this->create_file_submission($assign2, $user3, $student5filename); $submissionids = [ $submission1->id, $submission3->id ]; $userids = [ $user1->id, $user3->id ]; $data = $DB->get_records('files', ['contextid' => $context1->id, 'component' => 'assignsubmission_file']); $this->assertCount(6, $data); $data = $DB->get_records('assignsubmission_file', ['assignment' => $assign1->get_instance()->id]); $this->assertCount(3, $data); // Records in the second assignment (not being touched). $data = $DB->get_records('assignsubmission_file', ['assignment' => $assign2->get_instance()->id]); $this->assertCount(2, $data); $deletedata = new \mod_assign\privacy\assign_plugin_request_data($context1, $assign1); $deletedata->set_userids($userids); $deletedata->populate_submissions_and_grades(); \assignsubmission_file\privacy\provider::delete_submissions($deletedata); $data = $DB->get_records('files', ['contextid' => $context1->id, 'component' => 'assignsubmission_file']); $this->assertCount(2, $data); // Submission 1 and 3 have been removed. We should be left with submission2. $data = $DB->get_records('assignsubmission_file', ['assignment' => $assign1->get_instance()->id]); $this->assertCount(1, $data); // This should be untouched. $data = $DB->get_records('assignsubmission_file', ['assignment' => $assign2->get_instance()->id]); $this->assertCount(2, $data); } } file/tests/event/events_test.php 0000644 00000021506 15152704263 0013033 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Contains the event tests for the plugin. * * @package assignsubmission_file * @copyright 2013 Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_file\event; use mod_assign_test_generator; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/assign/tests/generator.php'); class events_test extends \advanced_testcase { // Use the generator helper. use mod_assign_test_generator; /** * Test that the assessable_uploaded event is fired when a file submission has been made. */ public function test_assessable_uploaded() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course); $context = $assign->get_context(); $cm = $assign->get_course_module(); $this->setUser($student->id); $submission = $assign->get_user_submission($student->id, true); $fs = get_file_storage(); $dummy = (object) array( 'contextid' => $context->id, 'component' => 'assignsubmission_file', 'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA, 'itemid' => $submission->id, 'filepath' => '/', 'filename' => 'myassignmnent.pdf' ); $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename); $dummy = (object) array( 'contextid' => $context->id, 'component' => 'assignsubmission_file', 'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA, 'itemid' => $submission->id, 'filepath' => '/', 'filename' => 'myassignmnent.png' ); $fi2 = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename); $files = $fs->get_area_files($context->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id, 'id', false); $data = new \stdClass(); $plugin = $assign->get_submission_plugin_by_type('file'); $sink = $this->redirectEvents(); $plugin->save($submission, $data); $events = $sink->get_events(); $this->assertCount(2, $events); $event = reset($events); $this->assertInstanceOf('\assignsubmission_file\event\assessable_uploaded', $event); $this->assertEquals($context->id, $event->contextid); $this->assertEquals($submission->id, $event->objectid); $this->assertCount(2, $event->other['pathnamehashes']); $this->assertEquals($fi->get_pathnamehash(), $event->other['pathnamehashes'][0]); $this->assertEquals($fi2->get_pathnamehash(), $event->other['pathnamehashes'][1]); $expected = new \stdClass(); $expected->modulename = 'assign'; $expected->cmid = $cm->id; $expected->itemid = $submission->id; $expected->courseid = $course->id; $expected->userid = $student->id; $expected->file = $files; $expected->files = $files; $expected->pathnamehashes = array($fi->get_pathnamehash(), $fi2->get_pathnamehash()); $this->assertEventLegacyData($expected, $event); $this->assertEventContextNotUsed($event); } /** * Test that the submission_created event is fired when a file submission is saved. */ public function test_submission_created() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course); $context = $assign->get_context(); $this->setUser($student->id); $submission = $assign->get_user_submission($student->id, true); $fs = get_file_storage(); $dummy = (object) array( 'contextid' => $context->id, 'component' => 'assignsubmission_file', 'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA, 'itemid' => $submission->id, 'filepath' => '/', 'filename' => 'myassignmnent.pdf' ); $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename); $dummy = (object) array( 'contextid' => $context->id, 'component' => 'assignsubmission_file', 'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA, 'itemid' => $submission->id, 'filepath' => '/', 'filename' => 'myassignmnent.png' ); $fi2 = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename); $files = $fs->get_area_files($context->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id, 'id', false); $data = new \stdClass(); $plugin = $assign->get_submission_plugin_by_type('file'); $sink = $this->redirectEvents(); $plugin->save($submission, $data); $events = $sink->get_events(); $this->assertCount(2, $events); // We want to test the last event fired. $event = $events[1]; $this->assertInstanceOf('\assignsubmission_file\event\submission_created', $event); $this->assertEquals($context->id, $event->contextid); $this->assertEquals($course->id, $event->courseid); $this->assertEquals($submission->id, $event->other['submissionid']); $this->assertEquals($submission->attemptnumber, $event->other['submissionattempt']); $this->assertEquals($submission->status, $event->other['submissionstatus']); $this->assertEquals($submission->userid, $event->relateduserid); } /** * Test that the submission_updated event is fired when a file submission is saved when an existing submission already exists. */ public function test_submission_updated() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course); $context = $assign->get_context(); $this->setUser($student->id); $submission = $assign->get_user_submission($student->id, true); $fs = get_file_storage(); $dummy = (object) array( 'contextid' => $context->id, 'component' => 'assignsubmission_file', 'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA, 'itemid' => $submission->id, 'filepath' => '/', 'filename' => 'myassignmnent.pdf' ); $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename); $dummy = (object) array( 'contextid' => $context->id, 'component' => 'assignsubmission_file', 'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA, 'itemid' => $submission->id, 'filepath' => '/', 'filename' => 'myassignmnent.png' ); $fi2 = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename); $files = $fs->get_area_files($context->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submission->id, 'id', false); $data = new \stdClass(); $plugin = $assign->get_submission_plugin_by_type('file'); $sink = $this->redirectEvents(); // Create a submission. $plugin->save($submission, $data); // Update a submission. $plugin->save($submission, $data); $events = $sink->get_events(); $this->assertCount(4, $events); // We want to test the last event fired. $event = $events[3]; $this->assertInstanceOf('\assignsubmission_file\event\submission_updated', $event); $this->assertEquals($context->id, $event->contextid); $this->assertEquals($course->id, $event->courseid); $this->assertEquals($submission->id, $event->other['submissionid']); $this->assertEquals($submission->attemptnumber, $event->other['submissionattempt']); $this->assertEquals($submission->status, $event->other['submissionstatus']); $this->assertEquals($submission->userid, $event->relateduserid); } } file/tests/locallib_test.php 0000644 00000015543 15152704263 0012173 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Tests for mod/assign/submission/file/locallib.php * * @package assignsubmission_file * @copyright 2016 Cameron Ball * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_file; use mod_assign_test_generator; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/assign/tests/generator.php'); /** * Unit tests for mod/assign/submission/file/locallib.php * * @copyright 2016 Cameron Ball * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class locallib_test extends \advanced_testcase { // Use the generator helper. use mod_assign_test_generator; /** * Test submission_is_empty * * @dataProvider submission_is_empty_testcases * @param string $data The file submission data * @param bool $expected The expected return value */ public function test_submission_is_empty($data, $expected) { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course, [ 'assignsubmission_file_enabled' => 1, 'assignsubmission_file_maxfiles' => 12, 'assignsubmission_file_maxsizebytes' => 10, ]); $this->setUser($student->id); $itemid = file_get_unused_draft_itemid(); $submission = (object)['files_filemanager' => $itemid]; $plugin = $assign->get_submission_plugin_by_type('file'); if ($data) { $data += ['contextid' => \context_user::instance($student->id)->id, 'itemid' => $itemid]; $fs = get_file_storage(); $fs->create_file_from_string((object)$data, 'Content of ' . $data['filename']); } $result = $plugin->submission_is_empty($submission); $this->assertTrue($result === $expected); } /** * Test that an empty directory is is not detected as a valid submission by submission_is_empty. */ public function test_submission_is_empty_directory_only() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course, [ 'assignsubmission_file_enabled' => 1, 'assignsubmission_file_maxfiles' => 12, 'assignsubmission_file_maxsizebytes' => 10, ]); $this->setUser($student->id); $itemid = file_get_unused_draft_itemid(); $submission = (object)['files_filemanager' => $itemid]; $plugin = $assign->get_submission_plugin_by_type('file'); $fs = get_file_storage(); $fs->create_directory( \context_user::instance($student->id)->id, 'user', 'draft', $itemid, '/subdirectory/' ); $this->assertTrue($plugin->submission_is_empty($submission)); } /** * Test new_submission_empty * * @dataProvider submission_is_empty_testcases * @param string $data The file submission data * @param bool $expected The expected return value */ public function test_new_submission_empty($data, $expected) { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course, [ 'assignsubmission_file_enabled' => 1, 'assignsubmission_file_maxfiles' => 12, 'assignsubmission_file_maxsizebytes' => 10, ]); $this->setUser($student); $itemid = file_get_unused_draft_itemid(); $submission = (object) ['files_filemanager' => $itemid]; if ($data) { $data += ['contextid' => \context_user::instance($student->id)->id, 'itemid' => $itemid]; $fs = get_file_storage(); $fs->create_file_from_string((object)$data, 'Content of ' . $data['filename']); } $result = $assign->new_submission_empty($submission); $this->assertTrue($result === $expected); } /** * Test that an empty directory is is not detected as a valid submission by new_submission_is_empty. */ public function test_new_submission_empty_directory_only() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course, [ 'assignsubmission_file_enabled' => 1, 'assignsubmission_file_maxfiles' => 12, 'assignsubmission_file_maxsizebytes' => 10, ]); $this->setUser($student->id); $itemid = file_get_unused_draft_itemid(); $submission = (object)['files_filemanager' => $itemid]; $plugin = $assign->get_submission_plugin_by_type('file'); $fs = get_file_storage(); $fs->create_directory( \context_user::instance($student->id)->id, 'user', 'draft', $itemid, '/subdirectory/' ); $this->assertTrue($assign->new_submission_empty($submission)); } /** * Dataprovider for the test_submission_is_empty testcase * * @return array of testcases */ public function submission_is_empty_testcases() { return [ 'With file' => [ [ 'component' => 'user', 'filearea' => 'draft', 'filepath' => '/', 'filename' => 'not_a_virus.exe' ], false ], 'With file in directory' => [ [ 'component' => 'user', 'filearea' => 'draft', 'filepath' => '/subdir/', 'filename' => 'not_a_virus.exe' ], false ], 'Without file' => [null, true] ]; } } file/tests/generator/lib.php 0000644 00000005226 15152704263 0012104 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. require_once("{$CFG->dirroot}/mod/assign/tests/generator/assignsubmission_subplugin_generator.php"); /** * Online Text assignment submission subplugin data generator. * * @package assignsubmission_file * @category test * @copyright 2021 Andrew Lyons <andrew@nicols.co.uk> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class assignsubmission_file_generator extends assignsubmission_subplugin_generator { /** * Add submission data in the correct format for a call to `assign::save_submission()` from a table containing * submission data for a single activity. * * Data should be added to the $submission object passed into the function. * * @param stdClass $submission The submission record to be modified * @param assign $assign The assignment being submitted to * @param array $data The data received */ public function add_submission_data(stdClass $submission, assign $assign, array $data): void { global $CFG; if (array_key_exists('file', $data)) { $files = explode(',', $data['file']); $itemid = file_get_unused_draft_itemid(); $fs = get_file_storage(); foreach ($files as $filepath) { // All paths are relative to $CFG->dirroot. $filepath = trim($filepath); $filepath = "{$CFG->dirroot}/{$filepath}"; $filename = basename($filepath); $fs->create_file_from_pathname((object) [ 'itemid' => $itemid, 'contextid' => context_user::instance($submission->userid)->id, 'component' => 'user', 'filearea' => 'draft', 'filepath' => '/', 'filename' => $filename, ], $filepath); } $submission->files_filemanager = $itemid; $submission->file_editor = [ 'itemid' => $itemid, ]; } } } file/tests/behat/file_type_restriction.feature 0000644 00000011022 15152704263 0015673 0 ustar 00 @mod @mod_assign @assignsubmission_file Feature: In an assignment, limit submittable file types In order to constrain student submissions for marking As a teacher I need to limit the submittable file types Background: Given the following "courses" exist: | fullname | shortname | category | groupmode | | Course 1 | C1 | 0 | 1 | And the following "users" exist: | username | firstname | lastname | email | | teacher1 | Teacher | 1 | teacher1@example.com | | student1 | Student | 1 | student1@example.com | And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | editingteacher | | student1 | C1 | student | And the following config values are set as admin: | filetypes | image/png;spreadsheet | assignsubmission_file | @javascript Scenario: File types validation for an assignment Given the following "activities" exist: | activity | course | name | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | | assign | C1 | Test assignment name | 1388534400 | 0 | 1 | 1 | 0 | And I am on the "Test assignment name" Activity page logged in as teacher1 And I navigate to "Settings" in current page administration When I set the field "Accepted file types" to "image/png;doesntexist;.anything;unreal/mimetype;nodot" And I press "Save and display" And I should see "Unknown file types: .doesntexist, .anything, unreal/mimetype, .nodot" And I set the field "Accepted file types" to "image/png;spreadsheet" And I press "Save and display" And I navigate to "Settings" in current page administration And the field "Accepted file types" matches value "image/png,spreadsheet" And I set the field "Accepted file types" to "" And I press "Choose" And I set the field "Image files" to "1" And I press "Save changes" And I press "Save and display" And I navigate to "Settings" in current page administration Then the field "Accepted file types" matches value "image" @javascript @_file_upload Scenario: Uploading permitted file types for an assignment Given the following "activities" exist: | activity | course | name | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | assignsubmission_file_filetypes | | assign | C1 | Test assignment name | 1388534400 | 0 | 1 | 3 | 0 | image/png,spreadsheet,.xml,.txt | And I am on the "Test assignment name" Activity page logged in as student1 When I press "Add submission" And I should see "Accepted file types" And I should see "Image (PNG)" And I should see "Spreadsheet files" And I should see "Text file" And I upload "lib/tests/fixtures/gd-logo.png" file to "File submissions" filemanager And I upload "lib/tests/fixtures/tabfile.csv" file to "File submissions" filemanager And I upload "lib/tests/fixtures/empty.txt" file to "File submissions" filemanager And I press "Save changes" Then "gd-logo.png" "link" should exist And "tabfile.csv" "link" should exist And "empty.txt" "link" should exist @javascript @_file_upload Scenario: No filetypes allows all Given the following "activities" exist: | activity | course | name | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | assignsubmission_file_filetypes | | assign | C1 | Test assignment name | 1388534400 | 0 | 1 | 2 | 0 | | And I am on the "Test assignment name" Activity page logged in as student1 When I press "Add submission" And I should not see "Accepted file types" And I upload "lib/tests/fixtures/gd-logo.png" file to "File submissions" filemanager And I upload "lib/tests/fixtures/tabfile.csv" file to "File submissions" filemanager And I press "Save changes" Then "gd-logo.png" "link" should exist And "tabfile.csv" "link" should exist file/backup/moodle2/restore_assignsubmission_file_subplugin.class.php 0000644 00000005125 15152704263 0022350 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the class for restore of this submission plugin * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * Restore subplugin class. * * Provides the necessary information * needed to restore one assign_submission subplugin. * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class restore_assignsubmission_file_subplugin extends restore_subplugin { /** * Returns the paths to be handled by the subplugin at workshop level * @return array */ protected function define_submission_subplugin_structure() { $paths = array(); $elename = $this->get_namefor('submission'); $elepath = $this->get_pathfor('/submission_file'); // We used get_recommended_name() so this works. $paths[] = new restore_path_element($elename, $elepath); return $paths; } /** * Processes one submission_file element * @param mixed $data * @return void */ public function process_assignsubmission_file_submission($data) { global $DB; $data = (object)$data; $data->assignment = $this->get_new_parentid('assign'); $oldsubmissionid = $data->submission; // The mapping is set in the restore for the core assign activity // when a submission node is processed. $data->submission = $this->get_mappingid('submission', $data->submission); $DB->insert_record('assignsubmission_file', $data); $this->add_related_files('assignsubmission_file', 'submission_files', 'submission', null, $oldsubmissionid); } } file/backup/moodle2/backup_assignsubmission_file_subplugin.class.php 0000644 00000005017 15152704263 0022132 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the class for backup of this submission plugin * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Provides the information to backup submission files * * This just adds its filearea to the annotations and records the number of files * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class backup_assignsubmission_file_subplugin extends backup_subplugin { /** * Returns the subplugin information to attach to submission element * @return backup_subplugin_element */ protected function define_submission_subplugin_structure() { // Create XML elements. $subplugin = $this->get_subplugin_element(); $subpluginwrapper = new backup_nested_element($this->get_recommended_name()); $subpluginelement = new backup_nested_element('submission_file', null, array('numfiles', 'submission')); // Connect XML elements into the tree. $subplugin->add_child($subpluginwrapper); $subpluginwrapper->add_child($subpluginelement); // Set source to populate the data. $subpluginelement->set_source_table('assignsubmission_file', array('submission' => backup::VAR_PARENTID)); // The parent is the submission. $subpluginelement->annotate_files('assignsubmission_file', 'submission_files', 'submission'); return $subplugin; } } file/settings.php 0000644 00000004452 15152704263 0010046 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file defines the admin settings for this plugin * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ // Note: This is on by default. $settings->add(new admin_setting_configcheckbox('assignsubmission_file/default', new lang_string('default', 'assignsubmission_file'), new lang_string('default_help', 'assignsubmission_file'), 1)); $settings->add(new admin_setting_configtext('assignsubmission_file/maxfiles', new lang_string('maxfiles', 'assignsubmission_file'), new lang_string('maxfiles_help', 'assignsubmission_file'), 20, PARAM_INT)); $settings->add(new admin_setting_filetypes('assignsubmission_file/filetypes', new lang_string('defaultacceptedfiletypes', 'assignsubmission_file'), new lang_string('acceptedfiletypes_help', 'assignsubmission_file'), '')); if (isset($CFG->maxbytes)) { $name = new lang_string('maximumsubmissionsize', 'assignsubmission_file'); $description = new lang_string('configmaxbytes', 'assignsubmission_file'); $maxbytes = get_config('assignsubmission_file', 'maxbytes'); $element = new admin_setting_configselect('assignsubmission_file/maxbytes', $name, $description, $CFG->maxbytes, get_max_upload_sizes($CFG->maxbytes, 0, 0, $maxbytes)); $settings->add($element); } file/lib.php 0000644 00000006031 15152704263 0006747 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the moodle hooks for the submission file plugin * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Serves assignment submissions and other files. * * @param mixed $course course or id of the course * @param mixed $cm course module or id of the course module * @param context $context * @param string $filearea * @param array $args * @param bool $forcedownload * @param array $options - List of options affecting file serving. * @return bool false if file not found, does not return if found - just send the file */ function assignsubmission_file_pluginfile($course, $cm, context $context, $filearea, $args, $forcedownload, array $options=array()) { global $DB, $CFG; if ($context->contextlevel != CONTEXT_MODULE) { return false; } require_login($course, false, $cm); $itemid = (int)array_shift($args); $record = $DB->get_record('assign_submission', array('id'=>$itemid), 'userid, assignment, groupid', MUST_EXIST); $userid = $record->userid; $groupid = $record->groupid; require_once($CFG->dirroot . '/mod/assign/locallib.php'); $assign = new assign($context, $cm, $course); if ($assign->get_instance()->id != $record->assignment) { return false; } if ($assign->get_instance()->teamsubmission && !$assign->can_view_group_submission($groupid)) { return false; } if (!$assign->get_instance()->teamsubmission && !$assign->can_view_submission($userid)) { return false; } $relativepath = implode('/', $args); $fullpath = "/{$context->id}/assignsubmission_file/$filearea/$itemid/$relativepath"; $fs = get_file_storage(); if (!($file = $fs->get_file_by_hash(sha1($fullpath))) || $file->is_directory()) { return false; } // Download MUST be forced - security! send_stored_file($file, 0, 0, true, $options); } file/version.php 0000644 00000002113 15152704263 0007663 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the version information for the file submission plugin * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $plugin->version = 2022112800; $plugin->requires = 2022111800; $plugin->component = 'assignsubmission_file'; file/classes/privacy/provider.php 0000644 00000016446 15152704263 0013160 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Privacy class for requesting user data. * * @package assignsubmission_file * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_file\privacy; defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/mod/assign/locallib.php'); use \core_privacy\local\metadata\collection; use \core_privacy\local\request\writer; use \core_privacy\local\request\contextlist; use \mod_assign\privacy\assign_plugin_request_data; /** * Privacy class for requesting user data. * * @package assignsubmission_file * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements \core_privacy\local\metadata\provider, \mod_assign\privacy\assignsubmission_provider, \mod_assign\privacy\assignsubmission_user_provider { /** * Return meta data about this plugin. * * @param collection $collection A list of information to add to. * @return collection Return the collection after adding to it. */ public static function get_metadata(collection $collection) : collection { $collection->link_subsystem('core_files', 'privacy:metadata:filepurpose'); return $collection; } /** * This is covered by mod_assign provider and the query on assign_submissions. * * @param int $userid The user ID that we are finding contexts for. * @param contextlist $contextlist A context list to add sql and params to for contexts. */ public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) { // This is already fetched from mod_assign. } /** * This is also covered by the mod_assign provider and it's queries. * * @param \mod_assign\privacy\useridlist $useridlist An object for obtaining user IDs of students. */ public static function get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) { // No need. } /** * If you have tables that contain userids and you can generate entries in your tables without creating an * entry in the assign_submission table then please fill in this method. * * @param userlist $userlist The userlist object */ public static function get_userids_from_context(\core_privacy\local\request\userlist $userlist) { // Not required. } /** * Export all user data for this plugin. * * @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful * information to help with exporting. */ public static function export_submission_user_data(assign_plugin_request_data $exportdata) { // We currently don't show submissions to teachers when exporting their data. $context = $exportdata->get_context(); if ($exportdata->get_user() != null) { return null; } $user = new \stdClass(); $assign = $exportdata->get_assign(); $plugin = $assign->get_plugin_by_type('assignsubmission', 'file'); $files = $plugin->get_files($exportdata->get_pluginobject(), $user); foreach ($files as $file) { $userid = $exportdata->get_pluginobject()->userid; writer::with_context($exportdata->get_context())->export_file($exportdata->get_subcontext(), $file); // Plagiarism data. $coursecontext = $context->get_course_context(); \core_plagiarism\privacy\provider::export_plagiarism_user_data($userid, $context, $exportdata->get_subcontext(), [ 'cmid' => $context->instanceid, 'course' => $coursecontext->instanceid, 'userid' => $userid, 'file' => $file ]); } } /** * Any call to this method should delete all user data for the context defined in the deletion_criteria. * * @param assign_plugin_request_data $requestdata Information useful for deleting user data. */ public static function delete_submission_for_context(assign_plugin_request_data $requestdata) { global $DB; \core_plagiarism\privacy\provider::delete_plagiarism_for_context($requestdata->get_context()); $fs = get_file_storage(); $fs->delete_area_files($requestdata->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA); // Delete records from assignsubmission_file table. $DB->delete_records('assignsubmission_file', ['assignment' => $requestdata->get_assign()->get_instance()->id]); } /** * A call to this method should delete user data (where practical) using the userid and submission. * * @param assign_plugin_request_data $deletedata Details about the user and context to focus the deletion. */ public static function delete_submission_for_userid(assign_plugin_request_data $deletedata) { global $DB; \core_plagiarism\privacy\provider::delete_plagiarism_for_user($deletedata->get_user()->id, $deletedata->get_context()); $submissionid = $deletedata->get_pluginobject()->id; $fs = get_file_storage(); $fs->delete_area_files($deletedata->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submissionid); $DB->delete_records('assignsubmission_file', ['assignment' => $deletedata->get_assignid(), 'submission' => $submissionid]); } /** * Deletes all submissions for the submission ids / userids provided in a context. * assign_plugin_request_data contains: * - context * - assign object * - submission ids (pluginids) * - user ids * @param assign_plugin_request_data $deletedata A class that contains the relevant information required for deletion. */ public static function delete_submissions(assign_plugin_request_data $deletedata) { global $DB; \core_plagiarism\privacy\provider::delete_plagiarism_for_users($deletedata->get_userids(), $deletedata->get_context()); if (empty($deletedata->get_submissionids())) { return; } $fs = get_file_storage(); list($sql, $params) = $DB->get_in_or_equal($deletedata->get_submissionids(), SQL_PARAMS_NAMED); $fs->delete_area_files_select($deletedata->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $sql, $params); $params['assignid'] = $deletedata->get_assignid(); $DB->delete_records_select('assignsubmission_file', "assignment = :assignid AND submission $sql", $params); } } file/classes/event/submission_updated.php 0000644 00000005451 15152704263 0014665 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * The assignsubmission_file submission_updated event. * * @package assignsubmission_file * @copyright 2014 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_file\event; defined('MOODLE_INTERNAL') || die(); /** * The assignsubmission_file submission_updated event class. * * @property-read array $other { * Extra information about the event. * * - int filesubmissioncount: The number of files uploaded. * } * * @package assignsubmission_file * @since Moodle 2.7 * @copyright 2014 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class submission_updated extends \mod_assign\event\submission_updated { /** * Init method. */ protected function init() { parent::init(); $this->data['objecttable'] = 'assignsubmission_file'; } /** * Returns non-localised description of what happened. * * @return string */ public function get_description() { $descriptionstring = "The user with id '$this->userid' updated a file submission and uploaded " . "'{$this->other['filesubmissioncount']}' file/s in the assignment with course module id " . "'$this->contextinstanceid'"; if (!empty($this->other['groupid'])) { $descriptionstring .= " for the group with id '{$this->other['groupid']}'."; } else { $descriptionstring .= "."; } return $descriptionstring; } /** * Custom validation. * * @throws \coding_exception * @return void */ protected function validate_data() { parent::validate_data(); if (!isset($this->other['filesubmissioncount'])) { throw new \coding_exception('The \'filesubmissioncount\' value must be set in other.'); } } public static function get_objectid_mapping() { // No mapping available for 'assignsubmission_file'. return array('db' => 'assignsubmission_file', 'restore' => \core\event\base::NOT_MAPPED); } } file/classes/event/submission_created.php 0000644 00000005451 15152704263 0014646 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * The assignsubmission_file submission_created event. * * @package assignsubmission_file * @copyright 2014 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_file\event; defined('MOODLE_INTERNAL') || die(); /** * The assignsubmission_file submission_created event class. * * @property-read array $other { * Extra information about the event. * * - int filesubmissioncount: The number of files uploaded. * } * * @package assignsubmission_file * @since Moodle 2.7 * @copyright 2014 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class submission_created extends \mod_assign\event\submission_created { /** * Init method. */ protected function init() { parent::init(); $this->data['objecttable'] = 'assignsubmission_file'; } /** * Returns non-localised description of what happened. * * @return string */ public function get_description() { $descriptionstring = "The user with id '$this->userid' created a file submission and uploaded " . "'{$this->other['filesubmissioncount']}' file/s in the assignment with course module id " . "'$this->contextinstanceid'"; if (!empty($this->other['groupid'])) { $descriptionstring .= " for the group with id '{$this->other['groupid']}'."; } else { $descriptionstring .= "."; } return $descriptionstring; } /** * Custom validation. * * @throws \coding_exception * @return void */ protected function validate_data() { parent::validate_data(); if (!isset($this->other['filesubmissioncount'])) { throw new \coding_exception('The \'filesubmissioncount\' value must be set in other.'); } } public static function get_objectid_mapping() { // No mapping available for 'assignsubmission_file'. return array('db' => 'assignsubmission_file', 'restore' => \core\event\base::NOT_MAPPED); } } file/classes/event/assessable_uploaded.php 0000644 00000007040 15152704263 0014762 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * The assignsubmission_file assessable uploaded event. * * @package assignsubmission_file * @copyright 2013 Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_file\event; defined('MOODLE_INTERNAL') || die(); /** * The assignsubmission_file assessable uploaded event class. * * @package assignsubmission_file * @since Moodle 2.6 * @copyright 2013 Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class assessable_uploaded extends \core\event\assessable_uploaded { /** * Legacy event files. * * @var array */ protected $legacyfiles = array(); /** * Returns description of what happened. * * @return string */ public function get_description() { return "The user with id '$this->userid' has uploaded a file to the submission with id '$this->objectid' " . "in the assignment activity with course module id '$this->contextinstanceid'."; } /** * Legacy event data if get_legacy_eventname() is not empty. * * @return \stdClass */ protected function get_legacy_eventdata() { $eventdata = new \stdClass(); $eventdata->modulename = 'assign'; $eventdata->cmid = $this->contextinstanceid; $eventdata->itemid = $this->objectid; $eventdata->courseid = $this->courseid; $eventdata->userid = $this->userid; if (count($this->legacyfiles) > 1) { $eventdata->files = $this->legacyfiles; } $eventdata->file = $this->legacyfiles; $eventdata->pathnamehashes = array_keys($this->legacyfiles); return $eventdata; } /** * Return the legacy event name. * * @return string */ public static function get_legacy_eventname() { return 'assessable_file_uploaded'; } /** * Return localised event name. * * @return string */ public static function get_name() { return get_string('eventassessableuploaded', 'assignsubmission_file'); } /** * Get URL related to the action. * * @return \moodle_url */ public function get_url() { return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid)); } /** * Sets the legacy event data. * * @param stdClass $legacyfiles legacy event data. * @return void */ public function set_legacy_files($legacyfiles) { $this->legacyfiles = $legacyfiles; } /** * Init method. * * @return void */ protected function init() { parent::init(); $this->data['objecttable'] = 'assign_submission'; } public static function get_objectid_mapping() { return array('db' => 'assign_submission', 'restore' => 'submission'); } } file/lang/en/assignsubmission_file.php 0000644 00000005163 15152704263 0014130 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Strings for component 'assignsubmission_file', language 'en' * * @package assignsubmission_file * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $string['acceptedfiletypes'] = 'Accepted file types'; $string['acceptedfiletypes_help'] = 'Accepted file types can be restricted by entering a list of file extensions. If the field is left empty, then all file types are allowed.'; $string['configmaxbytes'] = 'Maximum file size'; $string['countfiles'] = '{$a} files'; $string['default'] = 'Enabled by default'; $string['default_help'] = 'If set, this submission method will be enabled by default for all new assignments.'; $string['defaultacceptedfiletypes'] = 'Default accepted file types'; $string['enabled'] = 'File submissions'; $string['enabled_help'] = 'If enabled, students are able to upload one or more files as their submission.'; $string['eventassessableuploaded'] = 'A file has been uploaded.'; $string['file'] = 'File submissions'; $string['maxbytes'] = 'Maximum file size'; $string['maxfiles'] = 'Maximum files per submission'; $string['maxfiles_help'] = 'If file submissions are enabled, each assignment can be set to accept up to this number of files for their submission.'; $string['maxfilessubmission'] = 'Maximum number of uploaded files'; $string['maxfilessubmission_help'] = 'If file submissions are enabled, each student will be able to upload up to this number of files for their submission.'; $string['maximumsubmissionsize'] = 'Maximum submission size'; $string['maximumsubmissionsize_help'] = 'Files uploaded by students may be up to this size.'; $string['numfilesforlog'] = 'The number of file(s) : {$a} file(s).'; $string['pluginname'] = 'File submissions'; $string['privacy:metadata:filepurpose'] = 'The files loaded for this assignment submission'; $string['siteuploadlimit'] = 'Site upload limit'; $string['submissionfilearea'] = 'Uploaded submission files'; onlinetext/db/upgrade.php 0000644 00000002661 15152704263 0011474 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Upgrade code for install * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Stub for upgrade code * @param int $oldversion * @return bool */ function xmldb_assignsubmission_onlinetext_upgrade($oldversion) { global $CFG; // Automatically generated Moodle v3.9.0 release upgrade line. // Put any upgrade step following this. // Automatically generated Moodle v4.0.0 release upgrade line. // Put any upgrade step following this. // Automatically generated Moodle v4.1.0 release upgrade line. // Put any upgrade step following this. return true; } onlinetext/db/install.php 0000644 00000002762 15152704263 0011515 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Post-install code for the submission_onlinetext module. * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Code run after the assignsubmission_onlinetext module database tables have been created. * Moves the plugin to the top of the list (of 3) * @return bool */ function xmldb_assignsubmission_onlinetext_install() { global $CFG; // Set the correct initial order for the plugins. require_once($CFG->dirroot . '/mod/assign/adminlib.php'); $pluginmanager = new assign_plugin_manager('assignsubmission'); $pluginmanager->move_plugin('onlinetext', 'up'); $pluginmanager->move_plugin('onlinetext', 'up'); return true; } onlinetext/db/access.php 0000644 00000001664 15152704263 0011310 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Capability definitions for this module. * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $capabilities = array( ); onlinetext/db/install.xml 0000644 00000003001 15152704263 0011511 0 ustar 00 <?xml version="1.0" encoding="UTF-8" ?> <XMLDB PATH="mod/assign/submission/onlinetext/db" VERSION="20120423" COMMENT="XMLDB file for Moodle mod/assign/submission/onlinetext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/xmldb/xmldb.xsd" > <TABLES> <TABLE NAME="assignsubmission_onlinetext" COMMENT="Info about onlinetext submission"> <FIELDS> <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/> <FIELD NAME="assignment" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> <FIELD NAME="submission" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> <FIELD NAME="onlinetext" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="The text for this online text submission."/> <FIELD NAME="onlineformat" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The format for this online text submission."/> </FIELDS> <KEYS> <KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="The unique id for this onlinetext submission."/> <KEY NAME="assignment" TYPE="foreign" FIELDS="assignment" REFTABLE="assign" REFFIELDS="id" COMMENT="The assignment instance this online text submission relates to."/> <KEY NAME="submission" TYPE="foreign" FIELDS="submission" REFTABLE="assign_submission" REFFIELDS="id" COMMENT="The submission this online text submission relates to."/> </KEYS> </TABLE> </TABLES> </XMLDB> onlinetext/locallib.php 0000644 00000071167 15152704263 0011250 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the definition for the library class for onlinetext submission plugin * * This class provides all the functionality for the new assign module. * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); // File area for online text submission assignment. define('ASSIGNSUBMISSION_ONLINETEXT_FILEAREA', 'submissions_onlinetext'); /** * library class for onlinetext submission plugin extending submission plugin base class * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class assign_submission_onlinetext extends assign_submission_plugin { /** * Get the name of the online text submission plugin * @return string */ public function get_name() { return get_string('onlinetext', 'assignsubmission_onlinetext'); } /** * Get onlinetext submission information from the database * * @param int $submissionid * @return mixed */ private function get_onlinetext_submission($submissionid) { global $DB; return $DB->get_record('assignsubmission_onlinetext', array('submission'=>$submissionid)); } /** * Remove a submission. * * @param stdClass $submission The submission * @return boolean */ public function remove(stdClass $submission) { global $DB; $submissionid = $submission ? $submission->id : 0; if ($submissionid) { $DB->delete_records('assignsubmission_onlinetext', array('submission' => $submissionid)); } return true; } /** * Get the settings for onlinetext submission plugin * * @param MoodleQuickForm $mform The form to add elements to * @return void */ public function get_settings(MoodleQuickForm $mform) { global $CFG, $COURSE; $defaultwordlimit = $this->get_config('wordlimit') == 0 ? '' : $this->get_config('wordlimit'); $defaultwordlimitenabled = $this->get_config('wordlimitenabled'); $options = array('size' => '6', 'maxlength' => '6'); $name = get_string('wordlimit', 'assignsubmission_onlinetext'); // Create a text box that can be enabled/disabled for onlinetext word limit. $wordlimitgrp = array(); $wordlimitgrp[] = $mform->createElement('text', 'assignsubmission_onlinetext_wordlimit', '', $options); $wordlimitgrp[] = $mform->createElement('checkbox', 'assignsubmission_onlinetext_wordlimit_enabled', '', get_string('enable')); $mform->addGroup($wordlimitgrp, 'assignsubmission_onlinetext_wordlimit_group', $name, ' ', false); $mform->addHelpButton('assignsubmission_onlinetext_wordlimit_group', 'wordlimit', 'assignsubmission_onlinetext'); $mform->disabledIf('assignsubmission_onlinetext_wordlimit', 'assignsubmission_onlinetext_wordlimit_enabled', 'notchecked'); $mform->hideIf('assignsubmission_onlinetext_wordlimit', 'assignsubmission_onlinetext_enabled', 'notchecked'); // Add numeric rule to text field. $wordlimitgrprules = array(); $wordlimitgrprules['assignsubmission_onlinetext_wordlimit'][] = array(null, 'numeric', null, 'client'); $mform->addGroupRule('assignsubmission_onlinetext_wordlimit_group', $wordlimitgrprules); // Rest of group setup. $mform->setDefault('assignsubmission_onlinetext_wordlimit', $defaultwordlimit); $mform->setDefault('assignsubmission_onlinetext_wordlimit_enabled', $defaultwordlimitenabled); $mform->setType('assignsubmission_onlinetext_wordlimit', PARAM_INT); $mform->hideIf('assignsubmission_onlinetext_wordlimit_group', 'assignsubmission_onlinetext_enabled', 'notchecked'); } /** * Save the settings for onlinetext submission plugin * * @param stdClass $data * @return bool */ public function save_settings(stdClass $data) { if (empty($data->assignsubmission_onlinetext_wordlimit) || empty($data->assignsubmission_onlinetext_wordlimit_enabled)) { $wordlimit = 0; $wordlimitenabled = 0; } else { $wordlimit = $data->assignsubmission_onlinetext_wordlimit; $wordlimitenabled = 1; } $this->set_config('wordlimit', $wordlimit); $this->set_config('wordlimitenabled', $wordlimitenabled); return true; } /** * Add form elements for settings * * @param mixed $submission can be null * @param MoodleQuickForm $mform * @param stdClass $data * @return true if elements were added to the form */ public function get_form_elements($submission, MoodleQuickForm $mform, stdClass $data) { $elements = array(); $editoroptions = $this->get_edit_options(); $submissionid = $submission ? $submission->id : 0; if (!isset($data->onlinetext)) { $data->onlinetext = ''; } if (!isset($data->onlinetextformat)) { $data->onlinetextformat = editors_get_preferred_format(); } if ($submission) { $onlinetextsubmission = $this->get_onlinetext_submission($submission->id); if ($onlinetextsubmission) { $data->onlinetext = $onlinetextsubmission->onlinetext; $data->onlinetextformat = $onlinetextsubmission->onlineformat; } } $data = file_prepare_standard_editor($data, 'onlinetext', $editoroptions, $this->assignment->get_context(), 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $submissionid); $mform->addElement('editor', 'onlinetext_editor', $this->get_name(), null, $editoroptions); return true; } /** * Editor format options * * @return array */ private function get_edit_options() { $editoroptions = array( 'noclean' => false, 'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes' => $this->assignment->get_course()->maxbytes, 'context' => $this->assignment->get_context(), 'return_types' => (FILE_INTERNAL | FILE_EXTERNAL | FILE_CONTROLLED_LINK), 'removeorphaneddrafts' => true // Whether or not to remove any draft files which aren't referenced in the text. ); return $editoroptions; } /** * Save data to the database and trigger plagiarism plugin, * if enabled, to scan the uploaded content via events trigger * * @param stdClass $submission * @param stdClass $data * @return bool */ public function save(stdClass $submission, stdClass $data) { global $USER, $DB; $editoroptions = $this->get_edit_options(); $data = file_postupdate_standard_editor($data, 'onlinetext', $editoroptions, $this->assignment->get_context(), 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $submission->id); $onlinetextsubmission = $this->get_onlinetext_submission($submission->id); $fs = get_file_storage(); $files = $fs->get_area_files($this->assignment->get_context()->id, 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $submission->id, 'id', false); // Check word count before submitting anything. $exceeded = $this->check_word_count(trim($data->onlinetext)); if ($exceeded) { $this->set_error($exceeded); return false; } $params = array( 'context' => context_module::instance($this->assignment->get_course_module()->id), 'courseid' => $this->assignment->get_course()->id, 'objectid' => $submission->id, 'other' => array( 'pathnamehashes' => array_keys($files), 'content' => trim($data->onlinetext), 'format' => $data->onlinetext_editor['format'] ) ); if (!empty($submission->userid) && ($submission->userid != $USER->id)) { $params['relateduserid'] = $submission->userid; } if ($this->assignment->is_blind_marking()) { $params['anonymous'] = 1; } $event = \assignsubmission_onlinetext\event\assessable_uploaded::create($params); $event->trigger(); $groupname = null; $groupid = 0; // Get the group name as other fields are not transcribed in the logs and this information is important. if (empty($submission->userid) && !empty($submission->groupid)) { $groupname = $DB->get_field('groups', 'name', array('id' => $submission->groupid), MUST_EXIST); $groupid = $submission->groupid; } else { $params['relateduserid'] = $submission->userid; } $count = count_words($data->onlinetext); // Unset the objectid and other field from params for use in submission events. unset($params['objectid']); unset($params['other']); $params['other'] = array( 'submissionid' => $submission->id, 'submissionattempt' => $submission->attemptnumber, 'submissionstatus' => $submission->status, 'onlinetextwordcount' => $count, 'groupid' => $groupid, 'groupname' => $groupname ); if ($onlinetextsubmission) { $onlinetextsubmission->onlinetext = $data->onlinetext; $onlinetextsubmission->onlineformat = $data->onlinetext_editor['format']; $params['objectid'] = $onlinetextsubmission->id; $updatestatus = $DB->update_record('assignsubmission_onlinetext', $onlinetextsubmission); $event = \assignsubmission_onlinetext\event\submission_updated::create($params); $event->set_assign($this->assignment); $event->trigger(); return $updatestatus; } else { $onlinetextsubmission = new stdClass(); $onlinetextsubmission->onlinetext = $data->onlinetext; $onlinetextsubmission->onlineformat = $data->onlinetext_editor['format']; $onlinetextsubmission->submission = $submission->id; $onlinetextsubmission->assignment = $this->assignment->get_instance()->id; $onlinetextsubmission->id = $DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission); $params['objectid'] = $onlinetextsubmission->id; $event = \assignsubmission_onlinetext\event\submission_created::create($params); $event->set_assign($this->assignment); $event->trigger(); return $onlinetextsubmission->id > 0; } } /** * Return a list of the text fields that can be imported/exported by this plugin * * @return array An array of field names and descriptions. (name=>description, ...) */ public function get_editor_fields() { return array('onlinetext' => get_string('pluginname', 'assignsubmission_onlinetext')); } /** * Get the saved text content from the editor * * @param string $name * @param int $submissionid * @return string */ public function get_editor_text($name, $submissionid) { if ($name == 'onlinetext') { $onlinetextsubmission = $this->get_onlinetext_submission($submissionid); if ($onlinetextsubmission) { return $onlinetextsubmission->onlinetext; } } return ''; } /** * Get the content format for the editor * * @param string $name * @param int $submissionid * @return int */ public function get_editor_format($name, $submissionid) { if ($name == 'onlinetext') { $onlinetextsubmission = $this->get_onlinetext_submission($submissionid); if ($onlinetextsubmission) { return $onlinetextsubmission->onlineformat; } } return 0; } /** * Display onlinetext word count in the submission status table * * @param stdClass $submission * @param bool $showviewlink - If the summary has been truncated set this to true * @return string */ public function view_summary(stdClass $submission, & $showviewlink) { global $CFG; $onlinetextsubmission = $this->get_onlinetext_submission($submission->id); // Always show the view link. $showviewlink = true; if ($onlinetextsubmission) { // This contains the shortened version of the text plus an optional 'Export to portfolio' button. $text = $this->assignment->render_editor_content(ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $onlinetextsubmission->submission, $this->get_type(), 'onlinetext', 'assignsubmission_onlinetext', true); // The actual submission text. $onlinetext = trim($onlinetextsubmission->onlinetext); // The shortened version of the submission text. $shorttext = shorten_text($onlinetext, 140); $plagiarismlinks = ''; if (!empty($CFG->enableplagiarism)) { require_once($CFG->libdir . '/plagiarismlib.php'); $plagiarismlinks .= plagiarism_get_links(array('userid' => $submission->userid, 'content' => $onlinetext, 'cmid' => $this->assignment->get_course_module()->id, 'course' => $this->assignment->get_course()->id, 'assignment' => $submission->assignment)); } // We compare the actual text submission and the shortened version. If they are not equal, we show the word count. if ($onlinetext != $shorttext) { $wordcount = get_string('numwords', 'assignsubmission_onlinetext', count_words($onlinetext)); return $plagiarismlinks . $wordcount . $text; } else { return $plagiarismlinks . $text; } } return ''; } /** * Produce a list of files suitable for export that represent this submission. * * @param stdClass $submission - For this is the submission data * @param stdClass $user - This is the user record for this submission * @return array - return an array of files indexed by filename */ public function get_files(stdClass $submission, stdClass $user) { global $DB; $files = array(); $onlinetextsubmission = $this->get_onlinetext_submission($submission->id); // Note that this check is the same logic as the result from the is_empty function but we do // not call it directly because we already have the submission record. if ($onlinetextsubmission) { // Do not pass the text through format_text. The result may not be displayed in Moodle and // may be passed to external services such as document conversion or portfolios. $formattedtext = $this->assignment->download_rewrite_pluginfile_urls($onlinetextsubmission->onlinetext, $user, $this); $head = '<head><meta charset="UTF-8"></head>'; $submissioncontent = '<!DOCTYPE html><html>' . $head . '<body>'. $formattedtext . '</body></html>'; $filename = get_string('onlinetextfilename', 'assignsubmission_onlinetext'); $files[$filename] = array($submissioncontent); $fs = get_file_storage(); $fsfiles = $fs->get_area_files($this->assignment->get_context()->id, 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $submission->id, 'timemodified', false); foreach ($fsfiles as $file) { $files[$file->get_filename()] = $file; } } return $files; } /** * Display the saved text content from the editor in the view table * * @param stdClass $submission * @return string */ public function view(stdClass $submission) { global $CFG; $result = ''; $plagiarismlinks = ''; $onlinetextsubmission = $this->get_onlinetext_submission($submission->id); if ($onlinetextsubmission) { // Render for portfolio API. $result .= $this->assignment->render_editor_content(ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $onlinetextsubmission->submission, $this->get_type(), 'onlinetext', 'assignsubmission_onlinetext'); if (!empty($CFG->enableplagiarism)) { require_once($CFG->libdir . '/plagiarismlib.php'); $plagiarismlinks .= plagiarism_get_links(array('userid' => $submission->userid, 'content' => trim($onlinetextsubmission->onlinetext), 'cmid' => $this->assignment->get_course_module()->id, 'course' => $this->assignment->get_course()->id, 'assignment' => $submission->assignment)); } } return $plagiarismlinks . $result; } /** * Return true if this plugin can upgrade an old Moodle 2.2 assignment of this type and version. * * @param string $type old assignment subtype * @param int $version old assignment version * @return bool True if upgrade is possible */ public function can_upgrade($type, $version) { if ($type == 'online' && $version >= 2011112900) { return true; } return false; } /** * Upgrade the settings from the old assignment to the new plugin based one * * @param context $oldcontext - the database for the old assignment context * @param stdClass $oldassignment - the database for the old assignment instance * @param string $log record log events here * @return bool Was it a success? */ public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) { // No settings to upgrade. return true; } /** * Upgrade the submission from the old assignment to the new one * * @param context $oldcontext - the database for the old assignment context * @param stdClass $oldassignment The data record for the old assignment * @param stdClass $oldsubmission The data record for the old submission * @param stdClass $submission The data record for the new submission * @param string $log Record upgrade messages in the log * @return bool true or false - false will trigger a rollback */ public function upgrade(context $oldcontext, stdClass $oldassignment, stdClass $oldsubmission, stdClass $submission, & $log) { global $DB; $onlinetextsubmission = new stdClass(); $onlinetextsubmission->onlinetext = $oldsubmission->data1; $onlinetextsubmission->onlineformat = $oldsubmission->data2; $onlinetextsubmission->submission = $submission->id; $onlinetextsubmission->assignment = $this->assignment->get_instance()->id; if ($onlinetextsubmission->onlinetext === null) { $onlinetextsubmission->onlinetext = ''; } if ($onlinetextsubmission->onlineformat === null) { $onlinetextsubmission->onlineformat = editors_get_preferred_format(); } if (!$DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission) > 0) { $log .= get_string('couldnotconvertsubmission', 'mod_assign', $submission->userid); return false; } // Now copy the area files. $this->assignment->copy_area_files_for_upgrade($oldcontext->id, 'mod_assignment', 'submission', $oldsubmission->id, $this->assignment->get_context()->id, 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $submission->id); return true; } /** * Formatting for log info * * @param stdClass $submission The new submission * @return string */ public function format_for_log(stdClass $submission) { // Format the info for each submission plugin (will be logged). $onlinetextsubmission = $this->get_onlinetext_submission($submission->id); $onlinetextloginfo = ''; $onlinetextloginfo .= get_string('numwordsforlog', 'assignsubmission_onlinetext', count_words($onlinetextsubmission->onlinetext)); return $onlinetextloginfo; } /** * The assignment has been deleted - cleanup * * @return bool */ public function delete_instance() { global $DB; $DB->delete_records('assignsubmission_onlinetext', array('assignment'=>$this->assignment->get_instance()->id)); return true; } /** * No text is set for this plugin * * @param stdClass $submission * @return bool */ public function is_empty(stdClass $submission) { $onlinetextsubmission = $this->get_onlinetext_submission($submission->id); $wordcount = 0; $hasinsertedresources = false; if (isset($onlinetextsubmission->onlinetext)) { $wordcount = count_words(trim($onlinetextsubmission->onlinetext)); // Check if the online text submission contains video, audio or image elements // that can be ignored and stripped by count_words(). $hasinsertedresources = preg_match('/<\s*((video|audio)[^>]*>(.*?)<\s*\/\s*(video|audio)>)|(img[^>]*>(.*?))/', trim($onlinetextsubmission->onlinetext)); } return $wordcount == 0 && !$hasinsertedresources; } /** * Determine if a submission is empty * * This is distinct from is_empty in that it is intended to be used to * determine if a submission made before saving is empty. * * @param stdClass $data The submission data * @return bool */ public function submission_is_empty(stdClass $data) { if (!isset($data->onlinetext_editor)) { return true; } $wordcount = 0; $hasinsertedresources = false; if (isset($data->onlinetext_editor['text'])) { $wordcount = count_words(trim((string)$data->onlinetext_editor['text'])); // Check if the online text submission contains video, audio or image elements // that can be ignored and stripped by count_words(). $hasinsertedresources = preg_match('/<\s*((video|audio)[^>]*>(.*?)<\s*\/\s*(video|audio)>)|(img[^>]*>(.*?))/', trim((string)$data->onlinetext_editor['text'])); } return $wordcount == 0 && !$hasinsertedresources; } /** * Get file areas returns a list of areas this plugin stores files * @return array - An array of fileareas (keys) and descriptions (values) */ public function get_file_areas() { return array(ASSIGNSUBMISSION_ONLINETEXT_FILEAREA=>$this->get_name()); } /** * Copy the student's submission from a previous submission. Used when a student opts to base their resubmission * on the last submission. * @param stdClass $sourcesubmission * @param stdClass $destsubmission */ public function copy_submission(stdClass $sourcesubmission, stdClass $destsubmission) { global $DB; // Copy the files across (attached via the text editor). $contextid = $this->assignment->get_context()->id; $fs = get_file_storage(); $files = $fs->get_area_files($contextid, 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $sourcesubmission->id, 'id', false); foreach ($files as $file) { $fieldupdates = array('itemid' => $destsubmission->id); $fs->create_file_from_storedfile($fieldupdates, $file); } // Copy the assignsubmission_onlinetext record. $onlinetextsubmission = $this->get_onlinetext_submission($sourcesubmission->id); if ($onlinetextsubmission) { unset($onlinetextsubmission->id); $onlinetextsubmission->submission = $destsubmission->id; $DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission); } return true; } /** * Return a description of external params suitable for uploading an onlinetext submission from a webservice. * * @return external_description|null */ public function get_external_parameters() { $editorparams = array('text' => new external_value(PARAM_RAW, 'The text for this submission.'), 'format' => new external_value(PARAM_INT, 'The format for this submission'), 'itemid' => new external_value(PARAM_INT, 'The draft area id for files attached to the submission')); $editorstructure = new external_single_structure($editorparams, 'Editor structure', VALUE_OPTIONAL); return array('onlinetext_editor' => $editorstructure); } /** * Compare word count of onlinetext submission to word limit, and return result. * * @param string $submissiontext Onlinetext submission text from editor * @return string Error message if limit is enabled and exceeded, otherwise null */ public function check_word_count($submissiontext) { global $OUTPUT; $wordlimitenabled = $this->get_config('wordlimitenabled'); $wordlimit = $this->get_config('wordlimit'); if ($wordlimitenabled == 0) { return null; } // Count words and compare to limit. $wordcount = count_words($submissiontext); if ($wordcount <= $wordlimit) { return null; } else { $errormsg = get_string('wordlimitexceeded', 'assignsubmission_onlinetext', array('limit' => $wordlimit, 'count' => $wordcount)); return $OUTPUT->error_text($errormsg); } } /** * Return the plugin configs for external functions. * * @return array the list of settings * @since Moodle 3.2 */ public function get_config_for_external() { return (array) $this->get_config(); } } onlinetext/tests/privacy/provider_test.php 0000644 00000023226 15152704263 0015170 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Unit tests for assignsubmission_onlinetext. * * @package assignsubmission_onlinetext * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_onlinetext\privacy; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/assign/tests/privacy/provider_test.php'); /** * Unit tests for mod/assign/submission/onlinetext/classes/privacy/ * * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider_test extends \mod_assign\privacy\provider_test { /** * Convenience function for creating feedback data. * * @param object $assign assign object * @param stdClass $student user object * @param string $text Submission text. * @return array Submission plugin object and the submission object. */ protected function create_online_submission($assign, $student, $text) { global $CFG; $this->setUser($student->id); $submission = $assign->get_user_submission($student->id, true); $data = new \stdClass(); $data->onlinetext_editor = array( 'itemid' => file_get_unused_draft_itemid(), 'text' => $text, 'format' => FORMAT_PLAIN ); $submission = $assign->get_user_submission($student->id, true); $plugin = $assign->get_submission_plugin_by_type('onlinetext'); $plugin->save($submission, $data); return [$plugin, $submission]; } /** * Quick test to make sure that get_metadata returns something. */ public function test_get_metadata() { $collection = new \core_privacy\local\metadata\collection('assignsubmission_onlinetext'); $collection = \assignsubmission_onlinetext\privacy\provider::get_metadata($collection); $this->assertNotEmpty($collection); } /** * Test that submission files and text are exported for a user. */ public function test_export_submission_user_data() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $submissiontext = 'Just some text'; list($plugin, $submission) = $this->create_online_submission($assign, $user1, $submissiontext); $writer = \core_privacy\local\request\writer::with_context($context); $this->assertFalse($writer->has_any_data()); // The student should have some text submitted. $exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission, ['Attempt 1']); \assignsubmission_onlinetext\privacy\provider::export_submission_user_data($exportdata); $this->assertEquals($submissiontext, $writer->get_data(['Attempt 1', get_string('privacy:path', 'assignsubmission_onlinetext')])->text); } /** * Test that all submission files are deleted for this context. */ public function test_delete_submission_for_context() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studenttext = 'Student one\'s text.'; list($plugin, $submission) = $this->create_online_submission($assign, $user1, $studenttext); $studenttext2 = 'Student two\'s text.'; list($plugin2, $submission2) = $this->create_online_submission($assign, $user2, $studenttext2); // Only need the context and assign object in this plugin for this operation. $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign); \assignsubmission_onlinetext\privacy\provider::delete_submission_for_context($requestdata); // This checks that there is no content for these submissions. $this->assertTrue($plugin->is_empty($submission)); $this->assertTrue($plugin2->is_empty($submission2)); } /** * Test that the comments for a user are deleted. */ public function test_delete_submission_for_userid() { $this->resetAfterTest(); // Create course, assignment, submission, and then a feedback comment. $course = $this->getDataGenerator()->create_course(); // Student. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $assign = $this->create_instance(['course' => $course]); $context = $assign->get_context(); $studenttext = 'Student one\'s text.'; list($plugin, $submission) = $this->create_online_submission($assign, $user1, $studenttext); $studenttext2 = 'Student two\'s text.'; list($plugin2, $submission2) = $this->create_online_submission($assign, $user2, $studenttext2); // Need more data for this operation. $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission, [], $user1); \assignsubmission_onlinetext\privacy\provider::delete_submission_for_userid($requestdata); // This checks that there is no content for the first submission. $this->assertTrue($plugin->is_empty($submission)); // But there is for the second submission. $this->assertFalse($plugin2->is_empty($submission2)); } public function test_delete_submissions() { global $DB; $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $user3 = $this->getDataGenerator()->create_user(); // Only makes submissions in the second assignment. $user4 = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($user4->id, $course->id, 'student'); $assign1 = $this->create_instance(['course' => $course]); $assign2 = $this->create_instance(['course' => $course]); $context1 = $assign1->get_context(); $context2 = $assign2->get_context(); $student1text = 'Student one\'s text.'; list($plugin1, $submission1) = $this->create_online_submission($assign1, $user1, $student1text); $student2text = 'Student two\'s text.'; list($plugin2, $submission2) = $this->create_online_submission($assign1, $user2, $student2text); $student3text = 'Student two\'s text.'; list($plugin3, $submission3) = $this->create_online_submission($assign1, $user3, $student3text); // Now for submissions in assignment two. $student3text2 = 'Student two\'s text for the second assignment.'; list($plugin4, $submission4) = $this->create_online_submission($assign2, $user3, $student3text2); $student4text = 'Student four\'s text.'; list($plugin5, $submission5) = $this->create_online_submission($assign2, $user4, $student4text); $data = $DB->get_records('assignsubmission_onlinetext', ['assignment' => $assign1->get_instance()->id]); $this->assertCount(3, $data); // Delete the submissions for user 1 and 3. $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context1, $assign1); $requestdata->set_userids([$user1->id, $user2->id]); $requestdata->populate_submissions_and_grades(); \assignsubmission_onlinetext\privacy\provider::delete_submissions($requestdata); // There should only be one record left for assignment one. $data = $DB->get_records('assignsubmission_onlinetext', ['assignment' => $assign1->get_instance()->id]); $this->assertCount(1, $data); // Check that the second assignment has not been touched. $data = $DB->get_records('assignsubmission_onlinetext', ['assignment' => $assign2->get_instance()->id]); $this->assertCount(2, $data); } } onlinetext/tests/event/events_test.php 0000644 00000014554 15152704263 0014312 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Contains the event tests for the plugin. * * @package assignsubmission_onlinetext * @copyright 2013 Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_onlinetext\event; use mod_assign_test_generator; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/assign/tests/generator.php'); class events_test extends \advanced_testcase { // Use the generator helper. use mod_assign_test_generator; /** * Test that the assessable_uploaded event is fired when an online text submission is saved. */ public function test_assessable_uploaded() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course); $context = $assign->get_context(); $cm = $assign->get_course_module(); $this->setUser($student->id); $submission = $assign->get_user_submission($student->id, true); $data = (object) [ 'onlinetext_editor' => [ 'itemid' => file_get_unused_draft_itemid(), 'text' => 'Submission text', 'format' => FORMAT_PLAIN, ], ]; $sink = $this->redirectEvents(); $plugin = $assign->get_submission_plugin_by_type('onlinetext'); $plugin->save($submission, $data); $events = $sink->get_events(); $this->assertCount(2, $events); $event = reset($events); $this->assertInstanceOf('\assignsubmission_onlinetext\event\assessable_uploaded', $event); $this->assertEquals($context->id, $event->contextid); $this->assertEquals($submission->id, $event->objectid); $this->assertEquals(array(), $event->other['pathnamehashes']); $this->assertEquals(FORMAT_PLAIN, $event->other['format']); $this->assertEquals('Submission text', $event->other['content']); $expected = new \stdClass(); $expected->modulename = 'assign'; $expected->cmid = $cm->id; $expected->itemid = $submission->id; $expected->courseid = $course->id; $expected->userid = $student->id; $expected->content = 'Submission text'; $this->assertEventLegacyData($expected, $event); $this->assertEventContextNotUsed($event); } /** * Test that the submission_created event is fired when an onlinetext submission is saved. */ public function test_submission_created() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course); $context = $assign->get_context(); $this->setUser($student->id); $submission = $assign->get_user_submission($student->id, true); $data = (object) [ 'onlinetext_editor' => [ 'itemid' => file_get_unused_draft_itemid(), 'text' => 'Submission text', 'format' => FORMAT_PLAIN, ], ]; $sink = $this->redirectEvents(); $plugin = $assign->get_submission_plugin_by_type('onlinetext'); $plugin->save($submission, $data); $events = $sink->get_events(); $this->assertCount(2, $events); $event = $events[1]; $this->assertInstanceOf('\assignsubmission_onlinetext\event\submission_created', $event); $this->assertEquals($context->id, $event->contextid); $this->assertEquals($course->id, $event->courseid); $this->assertEquals($submission->id, $event->other['submissionid']); $this->assertEquals($submission->attemptnumber, $event->other['submissionattempt']); $this->assertEquals($submission->status, $event->other['submissionstatus']); $this->assertEquals($submission->userid, $event->relateduserid); } /** * Test that the submission_updated event is fired when an onlinetext * submission is saved and an existing submission already exists. */ public function test_submission_updated() { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course); $context = $assign->get_context(); $this->setUser($student->id); $submission = $assign->get_user_submission($student->id, true); $data = (object) [ 'onlinetext_editor' => [ 'itemid' => file_get_unused_draft_itemid(), 'text' => 'Submission text', 'format' => FORMAT_PLAIN, ], ]; $sink = $this->redirectEvents(); $plugin = $assign->get_submission_plugin_by_type('onlinetext'); $plugin->save($submission, $data); $sink->clear(); // Update a submission. $plugin->save($submission, $data); $events = $sink->get_events(); $this->assertCount(2, $events); $event = $events[1]; $this->assertInstanceOf('\assignsubmission_onlinetext\event\submission_updated', $event); $this->assertEquals($context->id, $event->contextid); $this->assertEquals($course->id, $event->courseid); $this->assertEquals($submission->id, $event->other['submissionid']); $this->assertEquals($submission->attemptnumber, $event->other['submissionattempt']); $this->assertEquals($submission->status, $event->other['submissionstatus']); $this->assertEquals($submission->userid, $event->relateduserid); } } onlinetext/tests/locallib_test.php 0000644 00000007621 15152704263 0013443 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Tests for mod/assign/submission/onlinetext/locallib.php * * @package assignsubmission_onlinetext * @copyright 2016 Cameron Ball * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_onlinetext; use mod_assign_test_generator; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/assign/tests/generator.php'); /** * Unit tests for mod/assign/submission/onlinetext/locallib.php * * @copyright 2016 Cameron Ball * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class locallib_test extends \advanced_testcase { // Use the generator helper. use mod_assign_test_generator; /** * Test submission_is_empty * * @dataProvider submission_is_empty_testcases * @param string $submissiontext The online text submission text * @param bool $expected The expected return value */ public function test_submission_is_empty($submissiontext, $expected) { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course, [ 'assignsubmission_onlinetext_enabled' => true, ]); $this->setUser($student->id); $plugin = $assign->get_submission_plugin_by_type('onlinetext'); $result = $plugin->submission_is_empty((object) [ 'onlinetext_editor' => [ 'text' => $submissiontext, ], ]); $this->assertTrue($result === $expected); } /** * Test new_submission_empty * * @dataProvider submission_is_empty_testcases * @param string $submissiontext The file submission data * @param bool $expected The expected return value */ public function test_new_submission_empty($submissiontext, $expected) { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); $assign = $this->create_instance($course, [ 'assignsubmission_onlinetext_enabled' => true, ]); $this->setUser($student->id); $result = $assign->new_submission_empty((object) [ 'onlinetext_editor' => [ 'text' => $submissiontext, ], ]); $this->assertTrue($result === $expected); } /** * Dataprovider for the test_submission_is_empty testcase * * @return array of testcases */ public function submission_is_empty_testcases() { return [ 'Empty submission string' => ['', true], 'Empty submission null' => [null, true], 'Value 0' => [0, false], 'String 0' => ['0', false], 'Text' => ['Ai! laurië lantar lassi súrinen, yéni únótimë ve rámar aldaron!', false], 'Image' => ['<img src="test.jpg" />', false], 'Video' => ['<video controls="true"><source src="test.mp4"></video>', false], 'Audio' => ['<audio controls="true"><source src="test.mp3"></audio>', false], ]; } } onlinetext/tests/generator/lib.php 0000644 00000003660 15152704263 0013356 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. require_once("{$CFG->dirroot}/mod/assign/tests/generator/assignsubmission_subplugin_generator.php"); /** * Online Text assignment submission subplugin data generator. * * @package assignsubmission_onlinetext * @category test * @copyright 2021 Andrew Lyons <andrew@nicols.co.uk> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class assignsubmission_onlinetext_generator extends assignsubmission_subplugin_generator { /** * Add submission data in the correct format for a call to `assign::save_submission()` from a table containing * submission data for a single activity. * * Data should be added to the $submission object passed into the function. * * @param stdClass $submission The submission record to be modified * @param assign $assign The assignment being submitted to * @param array $data The data received */ public function add_submission_data(stdClass $submission, assign $assign, array $data): void { if (array_key_exists('onlinetext', $data)) { $submission->onlinetext_editor = [ 'itemid' => file_get_unused_draft_itemid(), 'text' => $data['onlinetext'], 'format' => FORMAT_HTML, ]; } } } onlinetext/backup/moodle2/backup_assignsubmission_onlinetext_subplugin.class.php 0000644 00000005067 15152704263 0024663 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the class for backup of this submission plugin * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Provides the information to backup onlinetext submissions * * This just adds its filearea to the annotations and records the submissiontext and format * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class backup_assignsubmission_onlinetext_subplugin extends backup_subplugin { /** * Returns the subplugin information to attach to submission element * * @return backup_subplugin_element */ protected function define_submission_subplugin_structure() { // Create XML elements. $subplugin = $this->get_subplugin_element(); $subpluginwrapper = new backup_nested_element($this->get_recommended_name()); $subpluginelement = new backup_nested_element('submission_onlinetext', null, array('onlinetext', 'onlineformat', 'submission')); // Connect XML elements into the tree. $subplugin->add_child($subpluginwrapper); $subpluginwrapper->add_child($subpluginelement); // Set source to populate the data. $subpluginelement->set_source_table('assignsubmission_onlinetext', array('submission' => backup::VAR_PARENTID)); $subpluginelement->annotate_files('assignsubmission_onlinetext', 'submissions_onlinetext', 'submission'); return $subplugin; } } onlinetext/backup/moodle2/restore_assignsubmission_onlinetext_subplugin.class.php 0000644 00000005011 15152704263 0025066 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the class for restore of this submission plugin * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * Restore subplugin class. * * Provides the necessary information needed to restore * one assign_submission subplugin. * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class restore_assignsubmission_onlinetext_subplugin extends restore_subplugin { /** * Returns array the paths to be handled by the subplugin at assignment level * @return array */ protected function define_submission_subplugin_structure() { $paths = array(); $elename = $this->get_namefor('submission'); // We used get_recommended_name() so this works. $elepath = $this->get_pathfor('/submission_onlinetext'); $paths[] = new restore_path_element($elename, $elepath); return $paths; } /** * Processes one assignsubmission_onlinetext element * * @param mixed $data */ public function process_assignsubmission_onlinetext_submission($data) { global $DB; $data = (object)$data; $data->assignment = $this->get_new_parentid('assign'); $oldsubmissionid = $data->submission; // The mapping is set in the restore for the core assign activity // when a submission node is processed. $data->submission = $this->get_mappingid('submission', $data->submission); $DB->insert_record('assignsubmission_onlinetext', $data); $this->add_related_files('assignsubmission_onlinetext', 'submissions_onlinetext', 'submission', null, $oldsubmissionid); } } onlinetext/settings.php 0000644 00000002242 15152704263 0011313 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file defines the admin settings for this plugin * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $settings->add(new admin_setting_configcheckbox('assignsubmission_onlinetext/default', new lang_string('default', 'assignsubmission_onlinetext'), new lang_string('default_help', 'assignsubmission_onlinetext'), 0)); onlinetext/lib.php 0000644 00000006125 15152704263 0010225 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the moodle hooks for the submission onlinetext plugin * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Serves assignment submissions and other files. * * @param mixed $course course or id of the course * @param mixed $cm course module or id of the course module * @param context $context * @param string $filearea * @param array $args * @param bool $forcedownload * @param array $options - List of options affecting file serving. * @return bool false if file not found, does not return if found - just send the file */ function assignsubmission_onlinetext_pluginfile($course, $cm, context $context, $filearea, $args, $forcedownload, array $options=array()) { global $DB, $CFG; if ($context->contextlevel != CONTEXT_MODULE) { return false; } require_login($course, false, $cm); $itemid = (int)array_shift($args); $record = $DB->get_record('assign_submission', array('id'=>$itemid), 'userid, assignment, groupid', MUST_EXIST); $userid = $record->userid; $groupid = $record->groupid; require_once($CFG->dirroot . '/mod/assign/locallib.php'); $assign = new assign($context, $cm, $course); if ($assign->get_instance()->id != $record->assignment) { return false; } if ($assign->get_instance()->teamsubmission && !$assign->can_view_group_submission($groupid)) { return false; } if (!$assign->get_instance()->teamsubmission && !$assign->can_view_submission($userid)) { return false; } $relativepath = implode('/', $args); $fullpath = "/{$context->id}/assignsubmission_onlinetext/$filearea/$itemid/$relativepath"; $fs = get_file_storage(); if (!($file = $fs->get_file_by_hash(sha1($fullpath))) || $file->is_directory()) { return false; } // Download MUST be forced - security! send_stored_file($file, 0, 0, true, $options); } onlinetext/version.php 0000644 00000002135 15152704263 0011141 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * This file contains the version information for the onlinetext submission plugin * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $plugin->version = 2022112800; $plugin->requires = 2022111800; $plugin->component = 'assignsubmission_onlinetext'; onlinetext/classes/privacy/provider.php 0000644 00000021044 15152704263 0014420 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Privacy class for requesting user data. * * @package assignsubmission_onlinetext * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_onlinetext\privacy; defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/mod/assign/locallib.php'); use \core_privacy\local\metadata\collection; use \core_privacy\local\request\writer; use \core_privacy\local\request\contextlist; use \mod_assign\privacy\assign_plugin_request_data; /** * Privacy class for requesting user data. * * @package assignsubmission_onlinetext * @copyright 2018 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements \core_privacy\local\metadata\provider, \mod_assign\privacy\assignsubmission_provider, \mod_assign\privacy\assignsubmission_user_provider { /** * Return meta data about this plugin. * * @param collection $collection A list of information to add to. * @return collection Return the collection after adding to it. */ public static function get_metadata(collection $collection) : collection { $detail = [ 'assignment' => 'privacy:metadata:assignmentid', 'submission' => 'privacy:metadata:submissionpurpose', 'onlinetext' => 'privacy:metadata:textpurpose' ]; $collection->add_database_table('assignsubmission_onlinetext', $detail, 'privacy:metadata:tablepurpose'); $collection->link_subsystem('core_files', 'privacy:metadata:filepurpose'); return $collection; } /** * This is covered by mod_assign provider and the query on assign_submissions. * * @param int $userid The user ID that we are finding contexts for. * @param contextlist $contextlist A context list to add sql and params to for contexts. */ public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) { // This is already fetched from mod_assign. } /** * This is also covered by the mod_assign provider and it's queries. * * @param \mod_assign\privacy\useridlist $useridlist An object for obtaining user IDs of students. */ public static function get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) { // No need. } /** * If you have tables that contain userids and you can generate entries in your tables without creating an * entry in the assign_submission table then please fill in this method. * * @param \core_privacy\local\request\userlist $userlist The userlist object */ public static function get_userids_from_context(\core_privacy\local\request\userlist $userlist) { // Not required. } /** * Export all user data for this plugin. * * @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful * information to help with exporting. */ public static function export_submission_user_data(assign_plugin_request_data $exportdata) { // We currently don't show submissions to teachers when exporting their data. if ($exportdata->get_user() != null) { return null; } // Retrieve text for this submission. $assign = $exportdata->get_assign(); $plugin = $assign->get_plugin_by_type('assignsubmission', 'onlinetext'); $submission = $exportdata->get_pluginobject(); $editortext = $plugin->get_editor_text('onlinetext', $submission->id); $context = $exportdata->get_context(); if (!empty($editortext)) { $submissiontext = new \stdClass(); $currentpath = $exportdata->get_subcontext(); $currentpath[] = get_string('privacy:path', 'assignsubmission_onlinetext'); $submissiontext->text = writer::with_context($context)->rewrite_pluginfile_urls($currentpath, 'assignsubmission_onlinetext', 'submissions_onlinetext', $submission->id, $editortext); writer::with_context($context) ->export_area_files($currentpath, 'assignsubmission_onlinetext', 'submissions_onlinetext', $submission->id) // Add the text to the exporter. ->export_data($currentpath, $submissiontext); // Handle plagiarism data. $coursecontext = $context->get_course_context(); $userid = $submission->userid; \core_plagiarism\privacy\provider::export_plagiarism_user_data($userid, $context, $currentpath, [ 'cmid' => $context->instanceid, 'course' => $coursecontext->instanceid, 'userid' => $userid, 'content' => $editortext, 'assignment' => $submission->assignment ]); } } /** * Any call to this method should delete all user data for the context defined in the deletion_criteria. * * @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin. */ public static function delete_submission_for_context(assign_plugin_request_data $requestdata) { global $DB; \core_plagiarism\privacy\provider::delete_plagiarism_for_context($requestdata->get_context()); // Delete related files. $fs = get_file_storage(); $fs->delete_area_files($requestdata->get_context()->id, 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA); // Delete the records in the table. $DB->delete_records('assignsubmission_onlinetext', ['assignment' => $requestdata->get_assignid()]); } /** * A call to this method should delete user data (where practicle) from the userid and context. * * @param assign_plugin_request_data $deletedata Details about the user and context to focus the deletion. */ public static function delete_submission_for_userid(assign_plugin_request_data $deletedata) { global $DB; \core_plagiarism\privacy\provider::delete_plagiarism_for_user($deletedata->get_user()->id, $deletedata->get_context()); $submissionid = $deletedata->get_pluginobject()->id; // Delete related files. $fs = get_file_storage(); $fs->delete_area_files($deletedata->get_context()->id, 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $submissionid); // Delete the records in the table. $DB->delete_records('assignsubmission_onlinetext', ['assignment' => $deletedata->get_assignid(), 'submission' => $submissionid]); } /** * Deletes all submissions for the submission ids / userids provided in a context. * assign_plugin_request_data contains: * - context * - assign object * - submission ids (pluginids) * - user ids * @param assign_plugin_request_data $deletedata A class that contains the relevant information required for deletion. */ public static function delete_submissions(assign_plugin_request_data $deletedata) { global $DB; \core_plagiarism\privacy\provider::delete_plagiarism_for_users($deletedata->get_userids(), $deletedata->get_context()); if (empty($deletedata->get_submissionids())) { return; } $fs = get_file_storage(); list($sql, $params) = $DB->get_in_or_equal($deletedata->get_submissionids(), SQL_PARAMS_NAMED); $fs->delete_area_files_select($deletedata->get_context()->id, 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $sql, $params); $params['assignid'] = $deletedata->get_assignid(); $DB->delete_records_select('assignsubmission_onlinetext', "assignment = :assignid AND submission $sql", $params); } } onlinetext/classes/event/submission_updated.php 0000644 00000005544 15152704263 0016142 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * The assignsubmission_onlinetext submission_updated event. * * @package assignsubmission_onlinetext * @copyright 2014 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_onlinetext\event; defined('MOODLE_INTERNAL') || die(); /** * The assignsubmission_onlinetext submission_updated event class. * * @property-read array $other { * Extra information about the event. * * - int onlinetextwordcount: Word count of the online text submission. * } * * @package assignsubmission_onlinetext * @since Moodle 2.7 * @copyright 2014 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class submission_updated extends \mod_assign\event\submission_updated { /** * Init method. */ protected function init() { parent::init(); $this->data['objecttable'] = 'assignsubmission_onlinetext'; } /** * Returns non-localised description of what happened. * * @return string */ public function get_description() { $descriptionstring = "The user with id '$this->userid' updated an online text submission with " . "'{$this->other['onlinetextwordcount']}' words in the assignment with course module id " . "'$this->contextinstanceid'"; if (!empty($this->other['groupid'])) { $descriptionstring .= " for the group with id '{$this->other['groupid']}'."; } else { $descriptionstring .= "."; } return $descriptionstring; } /** * Custom validation. * * @throws \coding_exception * @return void */ protected function validate_data() { parent::validate_data(); if (!isset($this->other['onlinetextwordcount'])) { throw new \coding_exception('The \'onlinetextwordcount\' value must be set in other.'); } } public static function get_objectid_mapping() { // No mapping available for 'assignsubmission_onlinetext'. return array('db' => 'assignsubmission_onlinetext', 'restore' => \core\event\base::NOT_MAPPED); } } onlinetext/classes/event/submission_created.php 0000644 00000005544 15152704263 0016123 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * The assignsubmission_onlinetext submission_created event. * * @package assignsubmission_onlinetext * @copyright 2014 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_onlinetext\event; defined('MOODLE_INTERNAL') || die(); /** * The assignsubmission_onlinetext submission_created event class. * * @property-read array $other { * Extra information about the event. * * - int onlinetextwordcount: Word count of the online text submission. * } * * @package assignsubmission_onlinetext * @since Moodle 2.7 * @copyright 2014 Adrian Greeve <adrian@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class submission_created extends \mod_assign\event\submission_created { /** * Init method. */ protected function init() { parent::init(); $this->data['objecttable'] = 'assignsubmission_onlinetext'; } /** * Returns non-localised description of what happened. * * @return string */ public function get_description() { $descriptionstring = "The user with id '$this->userid' created an online text submission with " . "'{$this->other['onlinetextwordcount']}' words in the assignment with course module id " . "'$this->contextinstanceid'"; if (!empty($this->other['groupid'])) { $descriptionstring .= " for the group with id '{$this->other['groupid']}'."; } else { $descriptionstring .= "."; } return $descriptionstring; } /** * Custom validation. * * @throws \coding_exception * @return void */ protected function validate_data() { parent::validate_data(); if (!isset($this->other['onlinetextwordcount'])) { throw new \coding_exception('The \'onlinetextwordcount\' value must be set in other.'); } } public static function get_objectid_mapping() { // No mapping available for 'assignsubmission_onlinetext'. return array('db' => 'assignsubmission_onlinetext', 'restore' => \core\event\base::NOT_MAPPED); } } onlinetext/classes/event/assessable_uploaded.php 0000644 00000006515 15152704263 0016242 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * The assignsubmission_onlinetext assessable uploaded event. * * @package assignsubmission_onlinetext * @copyright 2013 Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace assignsubmission_onlinetext\event; defined('MOODLE_INTERNAL') || die(); /** * The assignsubmission_onlinetext assessable uploaded event class. * * @property-read array $other { * Extra information about event. * * - string format: (optional) content format. * } * * @package assignsubmission_onlinetext * @since Moodle 2.6 * @copyright 2013 Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class assessable_uploaded extends \core\event\assessable_uploaded { /** * Returns description of what happened. * * @return string */ public function get_description() { return "The user with id '$this->userid' has saved an online text submission with id '$this->objectid' " . "in the assignment activity with course module id '$this->contextinstanceid'."; } /** * Legacy event data if get_legacy_eventname() is not empty. * * @return stdClass */ protected function get_legacy_eventdata() { $eventdata = new \stdClass(); $eventdata->modulename = 'assign'; $eventdata->cmid = $this->contextinstanceid; $eventdata->itemid = $this->objectid; $eventdata->courseid = $this->courseid; $eventdata->userid = $this->userid; $eventdata->content = $this->other['content']; if ($this->other['pathnamehashes']) { $eventdata->pathnamehashes = $this->other['pathnamehashes']; } return $eventdata; } /** * Return the legacy event name. * * @return string */ public static function get_legacy_eventname() { return 'assessable_content_uploaded'; } /** * Return localised event name. * * @return string */ public static function get_name() { return get_string('eventassessableuploaded', 'assignsubmission_onlinetext'); } /** * Get URL related to the action. * * @return \moodle_url */ public function get_url() { return new \moodle_url('/mod/assign/view.php', array('id' => $this->contextinstanceid)); } /** * Init method. * * @return void */ protected function init() { parent::init(); $this->data['objecttable'] = 'assign_submission'; } public static function get_objectid_mapping() { return array('db' => 'assign_submission', 'restore' => 'submission'); } } onlinetext/lang/en/assignsubmission_onlinetext.php 0000644 00000005174 15152704263 0016656 0 ustar 00 <?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Strings for component 'assignsubmission_onlinetext', language 'en' * * @package assignsubmission_onlinetext * @copyright 2012 NetSpot {@link http://www.netspot.com.au} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $string['allowonlinetextsubmissions'] = 'Enabled'; $string['default'] = 'Enabled by default'; $string['default_help'] = 'If set, this submission method will be enabled by default for all new assignments.'; $string['enabled'] = 'Online text'; $string['enabled_help'] = 'If enabled, students are able to type rich text directly into an editor field for their submission.'; $string['eventassessableuploaded'] = 'An online text has been uploaded.'; $string['nosubmission'] = 'Nothing has been submitted for this assignment'; $string['onlinetext'] = 'Online text'; $string['onlinetextfilename'] = 'onlinetext.html'; $string['onlinetextsubmission'] = 'Allow online text submission'; $string['numwords'] = '({$a} words)'; $string['numwordsforlog'] = 'Submission word count: {$a} words'; $string['pluginname'] = 'Online text submissions'; $string['privacy:metadata:assignmentid'] = 'Assignment ID'; $string['privacy:metadata:filepurpose'] = 'Files that are embedded in the text submission.'; $string['privacy:metadata:submissionpurpose'] = 'The submission ID that links to submissions for the user.'; $string['privacy:metadata:tablepurpose'] = 'Stores the text submission for each attempt.'; $string['privacy:metadata:textpurpose'] = 'The actual text submitted for this attempt of the assignment.'; $string['privacy:path'] = 'Submission Text'; $string['wordlimit'] = 'Word limit'; $string['wordlimit_help'] = 'If online text submissions are enabled, this is the maximum number ' . 'of words that each student will be allowed to submit.'; $string['wordlimitexceeded'] = 'The word limit for this assignment is {$a->limit} words and you ' . 'are attempting to submit {$a->count} words. Please review your submission and try again.';
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | ���֧ߧ֧�ѧ�ڧ� ����ѧߧڧ��: 0 |
proxy
|
phpinfo
|
���ѧ����ۧܧ�