MDL-61308 assign_submission: Privacy code for user rights.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<?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 <[email protected]>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?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 <[email protected]>
|
||||
* @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 <[email protected]>
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?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 <[email protected]>
|
||||
* @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 <[email protected]>
|
||||
* @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');
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
$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';
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
<?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 <[email protected]>
|
||||
* @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 <[email protected]>
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?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 <[email protected]>
|
||||
* @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 <[email protected]>
|
||||
* @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]);
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ $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';
|
||||
// Deprecated since Moodle 3.4.
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
<?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 <[email protected]>
|
||||
* @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 <[email protected]>
|
||||
* @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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
<?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 <[email protected]>
|
||||
* @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 <[email protected]>
|
||||
* @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]);
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,15 @@ $string['nosubmission'] = 'Nothing has been submitted for this assignment';
|
||||
$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.';
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
<?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 <[email protected]>
|
||||
* @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 <[email protected]>
|
||||
* @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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
<?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() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user