diff --git a/mod/assign/classes/privacy/assignfeedback_user_provider.php b/mod/assign/classes/privacy/assignfeedback_user_provider.php new file mode 100644 index 00000000000..9048430a3bb --- /dev/null +++ b/mod/assign/classes/privacy/assignfeedback_user_provider.php @@ -0,0 +1,52 @@ +. + +/** + * This file contains the assignfeedback_user_provider interface. + * + * Assignment Sub plugins should implement this if they store personal information and can retrieve a userid. + * + * @package mod_assign + * @copyright 2018 Adrian Greeve + * + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace mod_assign\privacy; + +defined('MOODLE_INTERNAL') || die(); + +interface assignfeedback_user_provider extends \core_privacy\local\request\plugin\subplugin_provider { + + /** + * If you have tables that contain userids and you can generate entries in your tables without creating an + * entry in the assign_grades table then please fill in this method. + * + * @param \core_privacy\local\request\userlist $userlist The userlist object + */ + public static function get_userids_from_context(\core_privacy\local\request\userlist $userlist); + + /** + * Deletes all feedback for the grade ids / userids provided in a context. + * assign_plugin_request_data contains: + * - context + * - assign object + * - grade ids (pluginids) + * - user ids + * @param assign_plugin_request_data $deletedata A class that contains the relevant information required for deletion. + */ + public static function delete_feedback_for_grades(assign_plugin_request_data $deletedata); + +} \ No newline at end of file diff --git a/mod/assign/feedback/comments/classes/privacy/provider.php b/mod/assign/feedback/comments/classes/privacy/provider.php index ac9aa7fa58d..417c9e804c9 100644 --- a/mod/assign/feedback/comments/classes/privacy/provider.php +++ b/mod/assign/feedback/comments/classes/privacy/provider.php @@ -29,8 +29,6 @@ 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 \mod_assign\privacy\assignfeedback_provider; use \core_privacy\local\request\writer; use \core_privacy\local\request\contextlist; use \mod_assign\privacy\assign_plugin_request_data; @@ -43,7 +41,10 @@ use \mod_assign\privacy\useridlist; * @copyright 2018 Adrian Greeve * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class provider implements metadataprovider, assignfeedback_provider { +class provider implements + \core_privacy\local\metadata\provider, + \mod_assign\privacy\assignfeedback_provider, + \mod_assign\privacy\assignfeedback_user_provider { /** * Return meta data about this plugin. @@ -81,6 +82,16 @@ class provider implements metadataprovider, assignfeedback_provider { // Not required. } + /** + * If you have tables that contain userids and you can generate entries in your tables without creating an + * entry in the assign_grades table then please fill in this method. + * + * @param \core_privacy\local\request\userlist $userlist The userlist object + */ + public static function get_userids_from_context(\core_privacy\local\request\userlist $userlist) { + // Not required. + } + /** * Export all user data for this plugin. * @@ -119,7 +130,26 @@ class provider implements metadataprovider, assignfeedback_provider { */ public static function delete_feedback_for_grade(assign_plugin_request_data $requestdata) { global $DB; - $DB->delete_records('assignfeedback_comments', ['assignment' => $requestdata->get_assign()->get_instance()->id, + $DB->delete_records('assignfeedback_comments', ['assignment' => $requestdata->get_assignid(), 'grade' => $requestdata->get_pluginobject()->id]); } + + /** + * Deletes all feedback for the grade ids / userids provided in a context. + * assign_plugin_request_data contains: + * - context + * - assign object + * - grade ids (pluginids) + * - user ids + * @param assign_plugin_request_data $deletedata A class that contains the relevant information required for deletion. + */ + public static function delete_feedback_for_grades(assign_plugin_request_data $deletedata) { + global $DB; + if (empty($deletedata->get_gradeids())) { + return; + } + list($sql, $params) = $DB->get_in_or_equal($deletedata->get_gradeids(), SQL_PARAMS_NAMED); + $params['assignment'] = $deletedata->get_assignid(); + $DB->delete_records_select('assignfeedback_comments', "assignment = :assignment AND grade $sql", $params); + } } diff --git a/mod/assign/feedback/comments/tests/privacy_test.php b/mod/assign/feedback/comments/tests/privacy_test.php index 36494523ac4..b52b7ab9ed5 100644 --- a/mod/assign/feedback/comments/tests/privacy_test.php +++ b/mod/assign/feedback/comments/tests/privacy_test.php @@ -200,4 +200,67 @@ class assignfeedback_comments_privacy_testcase extends \mod_assign\tests\mod_ass $feedbackcomments = $plugin1->get_feedback_comments($grade2->id); $this->assertNotEmpty($feedbackcomments); } + + /** + * Test that a grade item is deleted for a user. + */ + public function test_delete_feedback_for_grades() { + $this->resetAfterTest(); + // Create course, assignment, submission, and then a feedback comment. + $course = $this->getDataGenerator()->create_course(); + // Student. + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + $user3 = $this->getDataGenerator()->create_user(); + $user4 = $this->getDataGenerator()->create_user(); + // Teacher. + $user5 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user4->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user5->id, $course->id, 'editingteacher'); + $assign1 = $this->create_instance(['course' => $course]); + $assign2 = $this->create_instance(['course' => $course]); + + $feedbacktext = '

first comment for this test

'; + list($plugin1, $grade1) = $this->create_feedback($assign1, $user1, $user5, 'Submission text', $feedbacktext); + $feedbacktext = '

Comment for second student.

'; + list($plugin2, $grade2) = $this->create_feedback($assign1, $user2, $user5, 'Submission text', $feedbacktext); + $feedbacktext = '

Comment for third student.

'; + list($plugin3, $grade3) = $this->create_feedback($assign1, $user3, $user5, 'Submission text', $feedbacktext); + $feedbacktext = '

Comment for third student in the second assignment.

'; + list($plugin4, $grade4) = $this->create_feedback($assign2, $user3, $user5, 'Submission text', $feedbacktext); + $feedbacktext = '

Comment for fourth student in the second assignment.

'; + list($plugin5, $grade5) = $this->create_feedback($assign2, $user4, $user5, 'Submission text', $feedbacktext); + + // Check that we have data. + $feedbackcomments = $plugin1->get_feedback_comments($grade1->id); + $this->assertNotEmpty($feedbackcomments); + $feedbackcomments = $plugin2->get_feedback_comments($grade2->id); + $this->assertNotEmpty($feedbackcomments); + $feedbackcomments = $plugin3->get_feedback_comments($grade3->id); + $this->assertNotEmpty($feedbackcomments); + $feedbackcomments = $plugin4->get_feedback_comments($grade4->id); + $this->assertNotEmpty($feedbackcomments); + $feedbackcomments = $plugin5->get_feedback_comments($grade5->id); + $this->assertNotEmpty($feedbackcomments); + + $deletedata = new \mod_assign\privacy\assign_plugin_request_data($assign1->get_context(), $assign1); + $deletedata->set_userids([$user1->id, $user3->id]); + $deletedata->populate_submissions_and_grades(); + assignfeedback_comments\privacy\provider::delete_feedback_for_grades($deletedata); + + // Check that grade 1 and grade 3 have been removed. + $feedbackcomments = $plugin1->get_feedback_comments($grade1->id); + $this->assertEmpty($feedbackcomments); + $feedbackcomments = $plugin2->get_feedback_comments($grade2->id); + $this->assertNotEmpty($feedbackcomments); + $feedbackcomments = $plugin3->get_feedback_comments($grade3->id); + $this->assertEmpty($feedbackcomments); + $feedbackcomments = $plugin4->get_feedback_comments($grade4->id); + $this->assertNotEmpty($feedbackcomments); + $feedbackcomments = $plugin5->get_feedback_comments($grade5->id); + $this->assertNotEmpty($feedbackcomments); + } } diff --git a/mod/assign/feedback/editpdf/classes/privacy/provider.php b/mod/assign/feedback/editpdf/classes/privacy/provider.php index 71706046d67..c3fb4da4bf0 100644 --- a/mod/assign/feedback/editpdf/classes/privacy/provider.php +++ b/mod/assign/feedback/editpdf/classes/privacy/provider.php @@ -29,7 +29,6 @@ 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 \mod_assign\privacy\assignfeedback_provider; use \core_privacy\local\request\writer; use \core_privacy\local\request\contextlist; @@ -43,7 +42,10 @@ use \mod_assign\privacy\useridlist; * @copyright 2018 Adrian Greeve * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class provider implements metadataprovider, assignfeedback_provider { +class provider implements + \core_privacy\local\metadata\provider, + \mod_assign\privacy\assignfeedback_provider, + \mod_assign\privacy\assignfeedback_user_provider { /** * Return meta data about this plugin. @@ -83,6 +85,16 @@ class provider implements metadataprovider, assignfeedback_provider { // Not required. } + /** + * If you have tables that contain userids and you can generate entries in your tables without creating an + * entry in the assign_grades table then please fill in this method. + * + * @param \core_privacy\local\request\userlist $userlist The userlist object + */ + public static function get_userids_from_context(\core_privacy\local\request\userlist $userlist) { + // Not required. + } + /** * Export all user data for this plugin. * @@ -127,21 +139,41 @@ class provider implements metadataprovider, assignfeedback_provider { * @param assign_plugin_request_data $requestdata Data useful for deleting user data. */ public static function delete_feedback_for_grade(assign_plugin_request_data $requestdata) { + $requestdata->set_userids([$requestdata->get_user()->id]); + $requestdata->populate_submissions_and_grades(); + self::delete_feedback_for_grades($requestdata); + } + + + /** + * Deletes all feedback for the grade ids / userids provided in a context. + * assign_plugin_request_data contains: + * - context + * - assign object + * - grade ids (pluginids) + * - user ids + * @param assign_plugin_request_data $deletedata A class that contains the relevant information required for deletion. + */ + public static function delete_feedback_for_grades(assign_plugin_request_data $deletedata) { global $DB; - $assign = $requestdata->get_assign(); + if (empty($deletedata->get_gradeids())) { + return; + } + + $assign = $deletedata->get_assign(); $plugin = $assign->get_plugin_by_type('assignfeedback', 'editpdf'); $fileareas = $plugin->get_file_areas(); $fs = get_file_storage(); + list($sql, $params) = $DB->get_in_or_equal($deletedata->get_gradeids(), SQL_PARAMS_NAMED); foreach ($fileareas as $filearea => $notused) { // Delete pdf files. - $fs->delete_area_files($requestdata->get_context()->id, 'assignfeedback_editpdf', - $filearea, $requestdata->get_pluginobject()->id); + $fs->delete_area_files_select($deletedata->get_context()->id, 'assignfeedback_editpdf', $filearea, $sql, $params); } // Remove table entries. - $DB->delete_records('assignfeedback_editpdf_annot', ['gradeid' => $requestdata->get_pluginobject()->id]); - $DB->delete_records('assignfeedback_editpdf_cmnt', ['gradeid' => $requestdata->get_pluginobject()->id]); + $DB->delete_records_select('assignfeedback_editpdf_annot', "gradeid $sql", $params); + $DB->delete_records_select('assignfeedback_editpdf_cmnt', "gradeid $sql", $params); // Submission records in assignfeedback_editpdf_queue will be cleaned up in a scheduled task } } diff --git a/mod/assign/feedback/editpdf/tests/privacy_test.php b/mod/assign/feedback/editpdf/tests/privacy_test.php index 2291d6cd09f..af07abe51b9 100644 --- a/mod/assign/feedback/editpdf/tests/privacy_test.php +++ b/mod/assign/feedback/editpdf/tests/privacy_test.php @@ -241,4 +241,78 @@ class assignfeedback_editpdf_privacy_testcase extends \mod_assign\tests\mod_assi // Check that user 2 data is still there. $this->assertFalse($plugin2->is_empty($grade2)); } + + /** + * Test that a grade item is deleted for a user. + */ + public function test_delete_feedback_for_grades() { + global $DB; + + $this->resetAfterTest(); + // Create course, assignment, submission, and then a feedback comment. + $course = $this->getDataGenerator()->create_course(); + // Students. + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + $user3 = $this->getDataGenerator()->create_user(); + $user4 = $this->getDataGenerator()->create_user(); + // Teacher. + $user5 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user4->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user5->id, $course->id, 'editingteacher'); + $assign1 = $this->create_instance(['course' => $course, + 'assignsubmission_file_enabled' => 1, + 'assignsubmission_file_maxfiles' => 1, + 'assignfeedback_editpdf_enabled' => 1, + 'assignsubmission_file_maxsizebytes' => 1000000]); + + $assign2 = $this->create_instance(['course' => $course, + 'assignsubmission_file_enabled' => 1, + 'assignsubmission_file_maxfiles' => 1, + 'assignfeedback_editpdf_enabled' => 1, + 'assignsubmission_file_maxsizebytes' => 1000000]); + + $context = $assign1->get_context(); + + list($plugin1, $grade1, $storedfile1) = $this->create_feedback($assign1, $user1, $user5); + list($plugin2, $grade2, $storedfile2) = $this->create_feedback($assign1, $user2, $user5); + list($plugin3, $grade3, $storedfile3) = $this->create_feedback($assign1, $user3, $user5); + list($plugin4, $grade4, $storedfile4) = $this->create_feedback($assign2, $user3, $user5); + list($plugin5, $grade5, $storedfile5) = $this->create_feedback($assign2, $user4, $user5); + + // Check that we have data. + $this->assertFalse($plugin1->is_empty($grade1)); + $this->assertFalse($plugin2->is_empty($grade2)); + $this->assertFalse($plugin3->is_empty($grade3)); + $this->assertFalse($plugin4->is_empty($grade4)); + $this->assertFalse($plugin5->is_empty($grade5)); + + // Check that there are also files generated. + $files = $DB->get_records('files', ['component' => 'assignfeedback_editpdf', 'filearea' => 'download']); + $this->assertCount(10, $files); + + $deletedata = new assign_plugin_request_data($context, $assign1); + $deletedata->set_userids([$user1->id, $user3->id]); + $deletedata->populate_submissions_and_grades(); + \assignfeedback_editpdf\privacy\provider::delete_feedback_for_grades($deletedata); + + // Check that we now have no data for user 1. + $this->assertTrue($plugin1->is_empty($grade1)); + // Check that user 2 data is still there. + $this->assertFalse($plugin2->is_empty($grade2)); + // User 3 in assignment 1 should be gone. + $this->assertTrue($plugin3->is_empty($grade3)); + // User 3 in assignment 2 should still be here. + $this->assertFalse($plugin4->is_empty($grade4)); + // User 4 in assignment 2 should also still be here. + $this->assertFalse($plugin5->is_empty($grade5)); + + // Check the files as well. + $files = $DB->get_records('files', ['component' => 'assignfeedback_editpdf', 'filearea' => 'download']); + // We should now only have six records here. + $this->assertCount(6, $files); + } } diff --git a/mod/assign/feedback/file/classes/privacy/provider.php b/mod/assign/feedback/file/classes/privacy/provider.php index f2f609fd2ff..839e9577531 100644 --- a/mod/assign/feedback/file/classes/privacy/provider.php +++ b/mod/assign/feedback/file/classes/privacy/provider.php @@ -29,9 +29,7 @@ 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\contextlist; -use \mod_assign\privacy\assignfeedback_provider; +use \core_privacy\local\request\contextlist; use \mod_assign\privacy\assign_plugin_request_data; use mod_assign\privacy\useridlist; @@ -42,7 +40,10 @@ use mod_assign\privacy\useridlist; * @copyright 2018 Adrian Greeve * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class provider implements metadataprovider, assignfeedback_provider { +class provider implements + \core_privacy\local\metadata\provider, + \mod_assign\privacy\assignfeedback_provider, + \mod_assign\privacy\assignfeedback_user_provider { /** * Return meta data about this plugin. @@ -75,6 +76,16 @@ class provider implements metadataprovider, assignfeedback_provider { // Not required. } + /** + * If you have tables that contain userids and you can generate entries in your tables without creating an + * entry in the assign_grades table then please fill in this method. + * + * @param \core_privacy\local\request\userlist $userlist The userlist object + */ + public static function get_userids_from_context(\core_privacy\local\request\userlist $userlist) { + // Not required. + } + /** * Export all user data for this plugin. * @@ -121,20 +132,40 @@ class provider implements metadataprovider, assignfeedback_provider { * @param assign_plugin_request_data $requestdata Data useful for deleting user data. */ public static function delete_feedback_for_grade(assign_plugin_request_data $requestdata) { + $requestdata->set_userids([$requestdata->get_user()->id]); + $requestdata->populate_submissions_and_grades(); + self::delete_feedback_for_grades($requestdata); + } + + + /** + * Deletes all feedback for the grade ids / userids provided in a context. + * assign_plugin_request_data contains: + * - context + * - assign object + * - grade ids (pluginids) + * - user ids + * @param assign_plugin_request_data $deletedata A class that contains the relevant information required for deletion. + */ + public static function delete_feedback_for_grades(assign_plugin_request_data $deletedata) { global $DB; - $assign = $requestdata->get_assign(); + if (empty($deletedata->get_gradeids())) { + return; + } + + $assign = $deletedata->get_assign(); $plugin = $assign->get_plugin_by_type('assignfeedback', 'file'); $fileareas = $plugin->get_file_areas(); $fs = get_file_storage(); + list($sql, $params) = $DB->get_in_or_equal($deletedata->get_gradeids(), SQL_PARAMS_NAMED); + $params['assignment'] = $deletedata->get_assignid(); foreach ($fileareas as $filearea => $notused) { // Delete feedback files. - $fs->delete_area_files($requestdata->get_context()->id, 'assignfeedback_file', $filearea, - $requestdata->get_pluginobject()->id); + $fs->delete_area_files_select($deletedata->get_context()->id, 'assignfeedback_file', $filearea, $sql, $params); } // Delete table entries. - $DB->delete_records('assignfeedback_file', ['assignment' => $requestdata->get_assign()->get_instance()->id, - 'grade' => $requestdata->get_pluginobject()->id]); + $DB->delete_records_select('assignfeedback_file', "assignment = :assignment AND grade $sql", $params); } } diff --git a/mod/assign/feedback/file/tests/privacy_test.php b/mod/assign/feedback/file/tests/privacy_test.php index 5537755d86c..38bd49b77f7 100644 --- a/mod/assign/feedback/file/tests/privacy_test.php +++ b/mod/assign/feedback/file/tests/privacy_test.php @@ -206,4 +206,63 @@ class assignfeedback_file_privacy_testcase extends \mod_assign\tests\mod_assign_ // User 2's data should still be intact. $this->assertFalse($plugin2->is_empty($grade2)); } + + /** + * Test that a grade item is deleted for a user. + */ + public function test_delete_feedback_for_grades() { + $this->resetAfterTest(); + // Create course, assignment, submission, and then a feedback comment. + $course = $this->getDataGenerator()->create_course(); + // Students. + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + $user3 = $this->getDataGenerator()->create_user(); + $user4 = $this->getDataGenerator()->create_user(); + // Teacher. + $user5 = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user4->id, $course->id, 'student'); + $this->getDataGenerator()->enrol_user($user5->id, $course->id, 'editingteacher'); + $assign1 = $this->create_instance(['course' => $course]); + $assign2 = $this->create_instance(['course' => $course]); + + $context = $assign1->get_context(); + + $feedbacktext = '

first comment for this test

'; + list($plugin1, $grade1) = $this->create_feedback($assign1, $user1, $user5, 'Submission text', $feedbacktext); + $feedbacktext = '

Comment for second submission.

'; + list($plugin2, $grade2) = $this->create_feedback($assign1, $user2, $user5, 'Submission text', $feedbacktext); + $feedbacktext = '

Comment for second submission.

'; + list($plugin3, $grade3) = $this->create_feedback($assign1, $user3, $user5, 'Submission text', $feedbacktext); + $feedbacktext = '

Comment for second submission.

'; + list($plugin4, $grade4) = $this->create_feedback($assign2, $user3, $user5, 'Submission text', $feedbacktext); + $feedbacktext = '

Comment for second submission.

'; + list($plugin5, $grade5) = $this->create_feedback($assign2, $user4, $user5, 'Submission text', $feedbacktext); + + // Check that we have data. + $this->assertFalse($plugin1->is_empty($grade1)); + $this->assertFalse($plugin2->is_empty($grade2)); + $this->assertFalse($plugin3->is_empty($grade3)); + $this->assertFalse($plugin4->is_empty($grade4)); + $this->assertFalse($plugin5->is_empty($grade5)); + + $deletedata = new assign_plugin_request_data($context, $assign1); + $deletedata->set_userids([$user1->id, $user3->id]); + $deletedata->populate_submissions_and_grades(); + \assignfeedback_file\privacy\provider::delete_feedback_for_grades($deletedata); + + // Check that we now have no data. + $this->assertTrue($plugin1->is_empty($grade1)); + // User 2's data should still be intact. + $this->assertFalse($plugin2->is_empty($grade2)); + // User 3's data in assignment 1 should be gone. + $this->assertTrue($plugin3->is_empty($grade3)); + // User 3's data in assignment 2 should still be intact. + $this->assertFalse($plugin4->is_empty($grade4)); + // User 4's data in assignment 2 should still be intact. + $this->assertFalse($plugin5->is_empty($grade5)); + } }