--- /dev/null
+<?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 assignsubmission_provider interface.
+ *
+ * Assignment Sub plugins should implement this if they store personal information.
+ *
+ * @package mod_assign
+ * @copyright 2018 Adrian Greeve <adrian@moodle.com>
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace mod_assign\privacy;
+
+use core_privacy\local\request\contextlist;
+
+defined('MOODLE_INTERNAL') || die();
+
+interface assignsubmission_provider extends \core_privacy\local\request\plugin\subplugin_provider {
+
+ /**
+ * Retrieves the contextids associated with the provided userid for this subplugin.
+ * NOTE if your subplugin must have an entry in the assign_submission table to work, then this
+ * method can be empty.
+ *
+ * @param int $userid The user ID to get context IDs for.
+ * @param \core_privacy\local\request\contextlist $contextlist Use add_from_sql with this object to add your context IDs.
+ */
+ public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist);
+
+ /**
+ * Returns student user ids related to the provided teacher ID. If it is possible that a student ID will not be returned by
+ * the sql query in \mod_assign\privacy\provider::find_grader_info() Then you need to provide some sql to retrive those
+ * student IDs. This is highly likely if you had to fill in get_context_for_userid_within_submission above.
+ *
+ * @param useridlist $useridlist A user ID list object that you can append your user IDs to.
+ */
+ public static function get_student_user_ids(useridlist $useridlist);
+
+ /**
+ * This method is used to export any user data this sub-plugin has using the assign_plugin_request_data object to get the
+ * context and userid.
+ * assign_plugin_request_data contains:
+ * - context
+ * - submission object
+ * - current path (subcontext)
+ * - user object
+ *
+ * @param assign_plugin_request_data $exportdata Information to use to export user data for this sub-plugin.
+ */
+ public static function export_submission_user_data(assign_plugin_request_data $exportdata);
+
+ /**
+ * Any call to this method should delete all user data for the context defined in the deletion_criteria.
+ * assign_plugin_request_data contains:
+ * - context
+ * - assign object
+ *
+ * @param assign_plugin_request_data $requestdata Information to use to delete user data for this submission.
+ */
+ public static function delete_submission_for_context(assign_plugin_request_data $requestdata);
+
+ /**
+ * A call to this method should delete user data (where practicle) from the userid and context.
+ * assign_plugin_request_data contains:
+ * - context
+ * - submission object
+ * - user object
+ * - assign object
+ *
+ * @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);
+}
--- /dev/null
+<?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 polyfill to allow a plugin to operate with Moodle 3.3 up.
+ *
+ * @package mod_assign
+ * @copyright 2018 Adrian Greeve <adrian@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace mod_assign\privacy;
+
+use core_privacy\local\request\contextlist;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The trait used to provide backwards compatability for third-party plugins.
+ *
+ * @copyright 2018 Adrian Greeve <adrian@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+trait submission_legacy_polyfill {
+
+ /**
+ * Retrieves the contextids associated with the provided userid for this subplugin.
+ * NOTE if your subplugin must have an entry in the assign_submission table to work, then this
+ * method can be empty.
+ *
+ * @param int $userid The user ID to get context IDs for.
+ * @param \core_privacy\local\request\contextlist $contextlist Use add_from_sql with this object to add your context IDs.
+ */
+ public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) {
+ return static::_get_context_for_userid_within_submission($userid, $contextlist);
+ }
+
+ /**
+ * Returns student user ids related to the provided teacher ID. If it is possible that a student ID will not be returned by
+ * the sql query in \mod_assign\privacy\provider::find_grader_info() Then you need to provide some sql to retrive those
+ * student IDs. This is highly likely if you had to fill in get_context_for_userid_within_submission above.
+ *
+ * @param useridlist $useridlist A user ID list object that you can append your user IDs to.
+ */
+ public static function get_student_user_ids(useridlist $useridlist) {
+ return static::_get_student_user_ids($useridlist);
+ }
+
+ /**
+ * This method is used to export any user data this sub-plugin has using the assign_plugin_request_data object to get the
+ * context and userid.
+ * assign_plugin_request_data contains:
+ * - context
+ * - submission object
+ * - current path (subcontext)
+ * - user object
+ *
+ * @param assign_plugin_request_data $exportdata Information to use to export user data for this sub-plugin.
+ */
+ public static function export_submission_user_data(assign_plugin_request_data $exportdata) {
+ return static::_export_submission_user_data($exportdata);
+ }
+
+ /**
+ * Any call to this method should delete all user data for the context defined in the deletion_criteria.
+ * assign_plugin_request_data contains:
+ * - context
+ * - assign object
+ *
+ * @param assign_plugin_request_data $requestdata Information to use to delete user data for this submission.
+ */
+ public static function delete_submission_for_context(assign_plugin_request_data $requestdata) {
+ return static::_delete_submission_for_context($requestdata);
+ }
+
+ /**
+ * A call to this method should delete user data (where practicle) from the userid and context.
+ * assign_plugin_request_data contains:
+ * - context
+ * - submission object
+ * - user object
+ * - assign object
+ *
+ * @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) {
+ return static::_delete_submission_for_userid($exportdata);
+ }
+}
--- /dev/null
+<?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 {
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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');
+ }
+}
$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';
--- /dev/null
+<?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
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/mod/assign/tests/privacy_test.php');
+
+/**
+ * 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 assignsubmission_comments_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
+
+ /**
+ * 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 mod_assign\privacy\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 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']);
+ $this->assertCount(2, $exportedcomments->comments);
+ $this->assertContains($studentcomment, $exportedcomments->comments[0]->content);
+ $this->assertContains($teachercomment, $exportedcomments->comments[1]->content);
+ }
+
+ /**
+ * 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);
+ }
+ }
+}
--- /dev/null
+<?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\metadata\provider as metadataprovider;
+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 metadataprovider, \mod_assign\privacy\assignsubmission_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.
+ }
+
+ /**
+ * 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 practicle) 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_assign()->get_instance()->id,
+ 'submission' => $submissionid]);
+ }
+}
$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';
// Deprecated since Moodle 3.4.
--- /dev/null
+<?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
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/mod/assign/tests/privacy_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 assignsubmission_file_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
+
+ /**
+ * 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));
+ }
+}
--- /dev/null
+<?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\metadata\provider as metadataprovider;
+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 metadataprovider, \mod_assign\privacy\assignsubmission_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.
+ }
+
+ /**
+ * 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();
+ $submissiontext->text = writer::with_context($context)->rewrite_pluginfile_urls([], '', '', '', $editortext);
+ $currentpath = $exportdata->get_subcontext();
+ $currentpath[] = get_string('privacy:path', 'assignsubmission_onlinetext');
+ 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_assign()->get_instance()->id]);
+ }
+
+ /**
+ * 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_assign()->get_instance()->id,
+ 'submission' => $submissionid]);
+ }
+}
$string['onlinetext'] = 'Online text';
$string['onlinetextfilename'] = 'onlinetext.html';
$string['onlinetextsubmission'] = 'Allow online text submission';
-$string['pluginname'] = 'Online text submissions';
$string['numwords'] = '({$a} words)';
$string['numwordsforlog'] = 'Submission word count: {$a} words';
+$string['pluginname'] = 'Online text submissions';
+$string['privacy:metadata:assignmentid'] = 'Assignment identifier';
+$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.';
--- /dev/null
+<?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
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/mod/assign/tests/privacy_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 assignsubmission_online_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
+
+ /**
+ * 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_file');
+ $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));
+ }
+}
--- /dev/null
+<?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 the privacy legacy polyfill for mod_assign.
+ *
+ * @package mod_assign
+ * @category test
+ * @copyright 2018 Adrian Greeve <adriangreeve.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/mod/assign/submissionplugin.php');
+require_once($CFG->dirroot . '/mod/assign/submission/comments/locallib.php');
+
+/**
+ * Unit tests for the assignment submission subplugins API's privacy legacy_polyfill.
+ *
+ * @copyright 2018 Adrian Greeve <adriangreeve.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class mod_assignsubmission_privacy_legacy_polyfill_test extends advanced_testcase {
+
+ /**
+ * Convenience function to create an instance of an assignment.
+ *
+ * @param array $params Array of parameters to pass to the generator
+ * @return assign The assign class.
+ */
+ protected function create_instance($params = array()) {
+ $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
+ $instance = $generator->create_instance($params);
+ $cm = get_coursemodule_from_instance('assign', $instance->id);
+ $context = \context_module::instance($cm->id);
+ return new \assign($context, $cm, $params['course']);
+ }
+
+ /**
+ * Test the get_context_for_userid_within_submission shim.
+ */
+ public function test_get_context_for_userid_within_submission() {
+
+ $userid = 21;
+ $contextlist = new \core_privacy\local\request\contextlist();
+ $mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
+ $mock->expects($this->once())
+ ->method('get_return_value')
+ ->with('_get_context_for_userid_within_submission', [$userid, $contextlist]);
+ test_legacy_polyfill_submission_provider::$mock = $mock;
+ test_legacy_polyfill_submission_provider::get_context_for_userid_within_submission($userid, $contextlist);
+ }
+
+ /**
+ * Test the get_student_user_ids shim.
+ */
+ public function test_get_student_user_ids() {
+ $teacherid = 107;
+ $assignid = 15;
+ $useridlist = new \mod_assign\privacy\useridlist($teacherid, $assignid);
+ $mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
+ $mock->expects($this->once())
+ ->method('get_return_value')
+ ->with('_get_student_user_ids', [$useridlist]);
+ test_legacy_polyfill_submission_provider::$mock = $mock;
+ test_legacy_polyfill_submission_provider::get_student_user_ids($useridlist);
+ }
+
+ /**
+ * Test the export_submission_user_data shim.
+ */
+ public function test_export_submission_user_data() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $assign = $this->create_instance(['course' => $course]);
+ $context = context_system::instance();
+ $subplugin = new assign_submission_comments($assign, 'comment');
+ $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
+ $mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
+ $mock->expects($this->once())
+ ->method('get_return_value')
+ ->with('_export_submission_user_data', [$requestdata]);
+ test_legacy_polyfill_submission_provider::$mock = $mock;
+ test_legacy_polyfill_submission_provider::export_submission_user_data($requestdata);
+ }
+
+ /**
+ * Test the delete_submission_for_context shim.
+ */
+ public function test_delete_submission_for_context() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $assign = $this->create_instance(['course' => $course]);
+ $context = context_system::instance();
+ $subplugin = new assign_submission_comments($assign, 'comment');
+ $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
+ $mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
+ $mock->expects($this->once())
+ ->method('get_return_value')
+ ->with('_delete_submission_for_context', [$requestdata]);
+ test_legacy_polyfill_submission_provider::$mock = $mock;
+ test_legacy_polyfill_submission_provider::delete_submission_for_context($requestdata);
+ }
+
+ /**
+ * Test the delete submission for grade shim.
+ */
+ public function test_delete_submission_for_userid() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $assign = $this->create_instance(['course' => $course]);
+ $context = context_system::instance();
+ $subplugin = new assign_submission_comments($assign, 'comment');
+ $requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
+ $mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
+ $mock->expects($this->once())
+ ->method('get_return_value')
+ ->with('_delete_submission_for_userid', [$requestdata]);
+ test_legacy_polyfill_submission_provider::$mock = $mock;
+ test_legacy_polyfill_submission_provider::delete_submission_for_userid($requestdata);
+ }
+}
+/**
+ * Legacy polyfill test class for the assignsubmission_provider.
+ *
+ * @copyright 2018 Adrian Greeve <adriangreeve.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class test_legacy_polyfill_submission_provider implements \mod_assign\privacy\assignsubmission_provider {
+ use \mod_assign\privacy\submission_legacy_polyfill;
+ /**
+ * @var test_legacy_polyfill_submission_provider $mock.
+ */
+ public static $mock = null;
+
+ /**
+ * Retrieves the contextids associated with the provided userid for this subplugin.
+ * NOTE if your subplugin must have an entry in the assign_grade table to work, then this
+ * method can be empty.
+ *
+ * @param int $userid The user ID to get context IDs for.
+ * @param contextlist $contextlist Use add_from_sql with this object to add your context IDs.
+ */
+ public static function _get_context_for_userid_within_submission(int $userid,
+ \core_privacy\local\request\contextlist $contextlist) {
+ static::$mock->get_return_value(__FUNCTION__, func_get_args());
+ }
+
+ /**
+ * Returns student user ids related to the provided teacher ID. If it is possible that a student ID will not be returned by
+ * the sql query in \mod_assign\privacy\provider::find_grader_info() Then you need to provide some sql to retrive those
+ * student IDs. This is highly likely if you had to fill in get_context_for_userid_within_submission above.
+ *
+ * @param useridlist $useridlist A list of user IDs of students graded by this user.
+ */
+ public static function _get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) {
+ static::$mock->get_return_value(__FUNCTION__, func_get_args());
+ }
+
+ /**
+ * This method is used to export any user data this sub-plugin has using the assign_plugin_request_data object to get the
+ * context and userid.
+ * assign_plugin_request_data contains:
+ * - context
+ * - grade object
+ * - current path (subcontext)
+ * - user object
+ *
+ * @param assign_plugin_request_data $exportdata Contains data to help export the user information.
+ */
+ public static function _export_submission_user_data(\mod_assign\privacy\assign_plugin_request_data $exportdata) {
+ static::$mock->get_return_value(__FUNCTION__, func_get_args());
+ }
+
+ /**
+ * Any call to this method should delete all user data for the context defined in the deletion_criteria.
+ * assign_plugin_request_data contains:
+ * - context
+ * - assign object
+ *
+ * @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
+ */
+ public static function _delete_submission_for_context(\mod_assign\privacy\assign_plugin_request_data $requestdata) {
+ static::$mock->get_return_value(__FUNCTION__, func_get_args());
+ }
+
+ /**
+ * A call to this method should delete user data (where practicle) from the userid and context.
+ * assign_plugin_request_data contains:
+ * - context
+ * - grade object
+ * - user object
+ * - assign object
+ *
+ * @param assign_plugin_request_data $requestdata Data useful for deleting user data.
+ */
+ public static function _delete_submission_for_userid(\mod_assign\privacy\assign_plugin_request_data $requestdata) {
+ static::$mock->get_return_value(__FUNCTION__, func_get_args());
+ }
+}
+/**
+ * Called inside the polyfill methods in the test polyfill provider, allowing us to ensure these are called with correct params.
+ *
+ * @copyright 2018 Adrian Greeve <adriangreeve.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class test_assignsubmission_legacy_polyfill_mock_wrapper {
+ /**
+ * Get the return value for the specified item.
+ */
+ public function get_return_value() {
+ }
+}