Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  •    1  <?php
       2  // This file is part of Moodle - http://moodle.org/
       3  //
       4  // Moodle is free software: you can redistribute it and/or modify
       5  // it under the terms of the GNU General Public License as published by
       6  // the Free Software Foundation, either version 3 of the License, or
       7  // (at your option) any later version.
       8  //
       9  // Moodle is distributed in the hope that it will be useful,
      10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12  // GNU General Public License for more details.
      13  //
      14  // You should have received a copy of the GNU General Public License
      15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
      16  
      17  /**
      18   * Base class for unit tests for mod_assign.
      19   *
      20   * @package    mod_assign
      21   * @copyright  2018 Adrian Greeve <adrian@moodle.com>
      22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      23   */
      24  
      25  namespace mod_assign\privacy;
      26  
      27  defined('MOODLE_INTERNAL') || die();
      28  
      29  global $CFG;
      30  require_once($CFG->dirroot . '/mod/assign/locallib.php');
      31  
      32  use core_privacy\tests\provider_testcase;
      33  use core_privacy\local\request\writer;
      34  use core_privacy\local\request\approved_contextlist;
      35  use mod_assign\privacy\provider;
      36  
      37  /**
      38   * Unit tests for mod/assign/classes/privacy/
      39   *
      40   * @copyright  2018 Adrian Greeve <adrian@moodle.com>
      41   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      42   */
      43  class provider_test extends provider_testcase {
      44  
      45      /**
      46       * Convenience method for creating a submission.
      47       *
      48       * @param  assign  $assign The assign object
      49       * @param  stdClass  $user The user object
      50       * @param  string  $submissiontext Submission text
      51       * @param  integer $attemptnumber The attempt number
      52       * @return object A submission object.
      53       */
      54      protected function create_submission($assign, $user, $submissiontext, $attemptnumber = 0) {
      55          $submission = $assign->get_user_submission($user->id, true, $attemptnumber);
      56          $submission->onlinetext_editor = ['text' => $submissiontext,
      57                                           'format' => FORMAT_MOODLE];
      58  
      59          $this->setUser($user);
      60          $notices = [];
      61          $assign->save_submission($submission, $notices);
      62          return $submission;
      63      }
      64  
      65      /**
      66       * Convenience function to create an instance of an assignment.
      67       *
      68       * @param array $params Array of parameters to pass to the generator
      69       * @return assign The assign class.
      70       */
      71      protected function create_instance($params = array()) {
      72          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
      73          $instance = $generator->create_instance($params);
      74          $cm = get_coursemodule_from_instance('assign', $instance->id);
      75          $context = \context_module::instance($cm->id);
      76          return new \assign($context, $cm, $params['course']);
      77      }
      78  
      79      /**
      80       * Test that getting the contexts for a user works.
      81       */
      82      public function test_get_contexts_for_userid() {
      83          global $DB;
      84          $this->resetAfterTest();
      85  
      86          $course1 = $this->getDataGenerator()->create_course();
      87          $course2 = $this->getDataGenerator()->create_course();
      88          $course3 = $this->getDataGenerator()->create_course();
      89  
      90          $user1 = $this->getDataGenerator()->create_user();
      91          $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
      92          $this->getDataGenerator()->enrol_user($user1->id, $course3->id, 'student');
      93          // Need a second user to create content in other assignments.
      94          $user2 = $this->getDataGenerator()->create_user();
      95          $this->getDataGenerator()->enrol_user($user2->id, $course2->id, 'student');
      96  
      97          // Create multiple assignments.
      98          // Assignment with a text submission.
      99          $assign1 = $this->create_instance(['course' => $course1]);
     100          // Assignment two in a different course that the user is not enrolled in.
     101          $assign2 = $this->create_instance(['course' => $course2]);
     102          // Assignment three has an entry in the override table.
     103          $assign3 = $this->create_instance(['course' => $course3, 'cutoffdate' => time()]);
     104          // Assignment four - blind marking.
     105          $assign4 = $this->create_instance(['course' => $course1, 'blindmarking' => 1]);
     106          // Assignment five - user flags.
     107          $assign5 = $this->create_instance(['course' => $course3]);
     108  
     109          // Override has to be manually inserted into the DB.
     110          $overridedata = new \stdClass();
     111          $overridedata->assignid = $assign3->get_instance()->id;
     112          $overridedata->userid = $user1->id;
     113          $overridedata->duedate = time();
     114          $DB->insert_record('assign_overrides', $overridedata);
     115          // Assign unique id for blind marking in assignment four for user 1.
     116          \assign::get_uniqueid_for_user_static($assign4->get_instance()->id, $user1->id);
     117          // Create an entry in the user flags table.
     118          $assign5->get_user_flags($user1->id, true);
     119  
     120          // The user will be in these contexts.
     121          $usercontextids = [
     122              $assign1->get_context()->id,
     123              $assign3->get_context()->id,
     124              $assign4->get_context()->id,
     125              $assign5->get_context()->id,
     126          ];
     127  
     128          $submission = new \stdClass();
     129          $submission->assignment = $assign1->get_instance()->id;
     130          $submission->userid = $user1->id;
     131          $submission->timecreated = time();
     132          $submission->onlinetext_editor = ['text' => 'Submission text',
     133                                           'format' => FORMAT_MOODLE];
     134  
     135          $this->setUser($user1);
     136          $notices = [];
     137          $assign1->save_submission($submission, $notices);
     138  
     139          // Create a submission for the second assignment.
     140          $submission->assignment = $assign2->get_instance()->id;
     141          $submission->userid = $user2->id;
     142          $this->setUser($user2);
     143          $assign2->save_submission($submission, $notices);
     144  
     145          $contextlist = provider::get_contexts_for_userid($user1->id);
     146          $this->assertEquals(count($usercontextids), count($contextlist->get_contextids()));
     147          // There should be no difference between the contexts.
     148          $this->assertEmpty(array_diff($usercontextids, $contextlist->get_contextids()));
     149      }
     150  
     151      /**
     152       * Test returning a list of user IDs related to a context (assign).
     153       */
     154      public function test_get_users_in_context() {
     155          global $DB;
     156  
     157          $this->resetAfterTest();
     158  
     159          $course = $this->getDataGenerator()->create_course();
     160  
     161          // Only made a comment on a submission.
     162          $user1 = $this->getDataGenerator()->create_user();
     163          // User 2 only has information about an activity override.
     164          $user2 = $this->getDataGenerator()->create_user();
     165          // User 3 made a submission.
     166          $user3 = $this->getDataGenerator()->create_user();
     167          // User 4 makes a submission and it is marked by the teacher.
     168          $user4 = $this->getDataGenerator()->create_user();
     169          // Grading and providing feedback as a teacher.
     170          $user5 = $this->getDataGenerator()->create_user();
     171          // This user has no entries and should not show up.
     172          $user6 = $this->getDataGenerator()->create_user();
     173  
     174          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
     175          $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
     176          $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student');
     177          $this->getDataGenerator()->enrol_user($user4->id, $course->id, 'student');
     178          $this->getDataGenerator()->enrol_user($user5->id, $course->id, 'editingteacher');
     179          $this->getDataGenerator()->enrol_user($user6->id, $course->id, 'student');
     180  
     181          $assign1 = $this->create_instance(['course' => $course,
     182                  'assignsubmission_onlinetext_enabled' => true,
     183                  'assignfeedback_comments_enabled' => true]);
     184          $assign2 = $this->create_instance(['course' => $course]);
     185  
     186          $context = $assign1->get_context();
     187  
     188          // Jam an entry in the comments table for user 1.
     189          $comment = (object) [
     190              'contextid' => $context->id,
     191              'component' => 'assignsubmission_comments',
     192              'commentarea' => 'submission_comments',
     193              'itemid' => 5,
     194              'content' => 'A comment by user 1',
     195              'format' => 0,
     196              'userid' => $user1->id,
     197              'timecreated' => time()
     198          ];
     199          $DB->insert_record('comments', $comment);
     200  
     201          $this->setUser($user5); // Set the user to the teacher.
     202  
     203          $overridedata = new \stdClass();
     204          $overridedata->assignid = $assign1->get_instance()->id;
     205          $overridedata->userid = $user2->id;
     206          $overridedata->duedate = time();
     207          $overridedata->allowsubmissionsfromdate = time();
     208          $overridedata->cutoffdate = time();
     209          $DB->insert_record('assign_overrides', $overridedata);
     210  
     211          $submissiontext = 'My first submission';
     212          $submission = $this->create_submission($assign1, $user3, $submissiontext);
     213  
     214          $submissiontext = 'My first submission';
     215          $submission = $this->create_submission($assign1, $user4, $submissiontext);
     216  
     217          $this->setUser($user5);
     218  
     219          $grade = '72.00';
     220          $teachercommenttext = 'This is better. Thanks.';
     221          $data = new \stdClass();
     222          $data->attemptnumber = 1;
     223          $data->grade = $grade;
     224          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
     225  
     226          // Give the submission a grade.
     227          $assign1->save_grade($user4->id, $data);
     228  
     229          $userlist = new \core_privacy\local\request\userlist($context, 'assign');
     230          provider::get_users_in_context($userlist);
     231          $userids = $userlist->get_userids();
     232          $this->assertTrue(in_array($user1->id, $userids));
     233          $this->assertTrue(in_array($user2->id, $userids));
     234          $this->assertTrue(in_array($user3->id, $userids));
     235          $this->assertTrue(in_array($user4->id, $userids));
     236          $this->assertTrue(in_array($user5->id, $userids));
     237          $this->assertFalse(in_array($user6->id, $userids));
     238      }
     239  
     240      /**
     241       * Test that a student with multiple submissions and grades is returned with the correct data.
     242       */
     243      public function test_export_user_data_student() {
     244          global $DB;
     245          $this->resetAfterTest();
     246          $course = $this->getDataGenerator()->create_course();
     247          $coursecontext = \context_course::instance($course->id);
     248  
     249          $user = $this->getDataGenerator()->create_user();
     250          $teacher = $this->getDataGenerator()->create_user();
     251          $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
     252          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
     253          $assign = $this->create_instance([
     254                  'course' => $course,
     255                  'name' => 'Assign 1',
     256                  'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
     257                  'maxattempts' => 3,
     258                  'assignsubmission_onlinetext_enabled' => true,
     259                  'assignfeedback_comments_enabled' => true
     260              ]);
     261  
     262          $context = $assign->get_context();
     263          // Create some submissions (multiple attempts) for a student.
     264          $submissiontext = 'My first submission';
     265          $submission = $this->create_submission($assign, $user, $submissiontext);
     266  
     267          $this->setUser($teacher);
     268  
     269          $overridedata = new \stdClass();
     270          $overridedata->assignid = $assign->get_instance()->id;
     271          $overridedata->userid = $user->id;
     272          $overridedata->duedate = time();
     273          $overridedata->allowsubmissionsfromdate = time();
     274          $overridedata->cutoffdate = time();
     275          $DB->insert_record('assign_overrides', $overridedata);
     276  
     277          $grade1 = '67.00';
     278          $teachercommenttext = 'Please try again.';
     279          $data = new \stdClass();
     280          $data->attemptnumber = 0;
     281          $data->grade = $grade1;
     282          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
     283  
     284          // Give the submission a grade.
     285          $assign->save_grade($user->id, $data);
     286  
     287          $submissiontext2 = 'My second submission';
     288          $submission = $this->create_submission($assign, $user, $submissiontext2, 1);
     289  
     290          $this->setUser($teacher);
     291  
     292          $grade2 = '72.00';
     293          $teachercommenttext2 = 'This is better. Thanks.';
     294          $data = new \stdClass();
     295          $data->attemptnumber = 1;
     296          $data->grade = $grade2;
     297          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext2, 'format' => FORMAT_MOODLE];
     298  
     299          // Give the submission a grade.
     300          $assign->save_grade($user->id, $data);
     301  
     302          $writer = writer::with_context($context);
     303          $this->assertFalse($writer->has_any_data());
     304  
     305          // The student should have some text submitted.
     306          // Add the course context as well to make sure there is no error.
     307          $approvedlist = new approved_contextlist($user, 'mod_assign', [$context->id, $coursecontext->id]);
     308          provider::export_user_data($approvedlist);
     309  
     310          // Check that we have general details about the assignment.
     311          $this->assertEquals('Assign 1', $writer->get_data()->name);
     312          // Check Submissions.
     313          $this->assertEquals($submissiontext, $writer->get_data(['attempt 1', 'Submission Text'])->text);
     314          $this->assertEquals($submissiontext2, $writer->get_data(['attempt 2', 'Submission Text'])->text);
     315          $this->assertEquals(1, $writer->get_data(['attempt 1', 'submission'])->attemptnumber);
     316          $this->assertEquals(2, $writer->get_data(['attempt 2', 'submission'])->attemptnumber);
     317          // Check grades.
     318          $this->assertEquals((float)$grade1, $writer->get_data(['attempt 1', 'grade'])->grade);
     319          $this->assertEquals((float)$grade2, $writer->get_data(['attempt 2', 'grade'])->grade);
     320          // Check feedback.
     321          $this->assertStringContainsString($teachercommenttext, $writer->get_data(['attempt 1', 'Feedback comments'])->commenttext);
     322          $this->assertStringContainsString($teachercommenttext2, $writer->get_data(['attempt 2', 'Feedback comments'])->commenttext);
     323  
     324          // Check override data was exported correctly.
     325          $overrideexport = $writer->get_data(['Overrides']);
     326          $this->assertEquals(\core_privacy\local\request\transform::datetime($overridedata->duedate),
     327                  $overrideexport->duedate);
     328          $this->assertEquals(\core_privacy\local\request\transform::datetime($overridedata->cutoffdate),
     329                  $overrideexport->cutoffdate);
     330          $this->assertEquals(\core_privacy\local\request\transform::datetime($overridedata->allowsubmissionsfromdate),
     331                  $overrideexport->allowsubmissionsfromdate);
     332      }
     333  
     334      /**
     335       * Tests the data returned for a teacher.
     336       */
     337      public function test_export_user_data_teacher() {
     338          $this->resetAfterTest();
     339          $course = $this->getDataGenerator()->create_course();
     340          $coursecontext = \context_course::instance($course->id);
     341  
     342          $user1 = $this->getDataGenerator()->create_user();
     343          $user2 = $this->getDataGenerator()->create_user();
     344          $teacher = $this->getDataGenerator()->create_user();
     345          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
     346          $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
     347          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
     348          $assign = $this->create_instance([
     349                  'course' => $course,
     350                  'name' => 'Assign 1',
     351                  'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
     352                  'maxattempts' => 3,
     353                  'assignsubmission_onlinetext_enabled' => true,
     354                  'assignfeedback_comments_enabled' => true
     355              ]);
     356  
     357          $context = $assign->get_context();
     358  
     359          // Create and grade some submissions from the students.
     360          $submissiontext = 'My first submission';
     361          $submission = $this->create_submission($assign, $user1, $submissiontext);
     362  
     363          $this->setUser($teacher);
     364  
     365          $grade1 = '54.00';
     366          $teachercommenttext = 'Comment on user 1 attempt 1.';
     367          $data = new \stdClass();
     368          $data->attemptnumber = 0;
     369          $data->grade = $grade1;
     370          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
     371  
     372          // Give the submission a grade.
     373          $assign->save_grade($user1->id, $data);
     374  
     375          // Create and grade some submissions from the students.
     376          $submissiontext2 = 'My first submission for user 2';
     377          $submission = $this->create_submission($assign, $user2, $submissiontext2);
     378  
     379          $this->setUser($teacher);
     380  
     381          $grade2 = '56.00';
     382          $teachercommenttext2 = 'Comment on user 2 first attempt.';
     383          $data = new \stdClass();
     384          $data->attemptnumber = 0;
     385          $data->grade = $grade2;
     386          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext2, 'format' => FORMAT_MOODLE];
     387  
     388          // Give the submission a grade.
     389          $assign->save_grade($user2->id, $data);
     390  
     391          // Create and grade some submissions from the students.
     392          $submissiontext3 = 'My second submission for user 2';
     393          $submission = $this->create_submission($assign, $user2, $submissiontext3, 1);
     394  
     395          $this->setUser($teacher);
     396  
     397          $grade3 = '83.00';
     398          $teachercommenttext3 = 'Comment on user 2 another attempt.';
     399          $data = new \stdClass();
     400          $data->attemptnumber = 1;
     401          $data->grade = $grade3;
     402          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext3, 'format' => FORMAT_MOODLE];
     403  
     404          // Give the submission a grade.
     405          $assign->save_grade($user2->id, $data);
     406  
     407          // Set up some flags.
     408          $duedate = time();
     409          $flagdata = $assign->get_user_flags($teacher->id, true);
     410          $flagdata->mailed = 1;
     411          $flagdata->extensionduedate = $duedate;
     412          $assign->update_user_flags($flagdata);
     413  
     414          $writer = writer::with_context($context);
     415          $this->assertFalse($writer->has_any_data());
     416  
     417          // The student should have some text submitted.
     418          $approvedlist = new approved_contextlist($teacher, 'mod_assign', [$context->id, $coursecontext->id]);
     419          provider::export_user_data($approvedlist);
     420  
     421          // Check flag metadata.
     422          $metadata = $writer->get_all_metadata();
     423          $this->assertEquals(\core_privacy\local\request\transform::yesno(1), $metadata['mailed']->value);
     424          $this->assertEquals(\core_privacy\local\request\transform::datetime($duedate), $metadata['extensionduedate']->value);
     425  
     426          // Check for student grades given.
     427          $student1grade = $writer->get_data(['studentsubmissions', $user1->id, 'attempt 1', 'grade']);
     428          $this->assertEquals((float)$grade1, $student1grade->grade);
     429          $student2grade1 = $writer->get_data(['studentsubmissions', $user2->id, 'attempt 1', 'grade']);
     430          $this->assertEquals((float)$grade2, $student2grade1->grade);
     431          $student2grade2 = $writer->get_data(['studentsubmissions', $user2->id, 'attempt 2', 'grade']);
     432          $this->assertEquals((float)$grade3, $student2grade2->grade);
     433          // Check for feedback given to students.
     434          $this->assertStringContainsString($teachercommenttext, $writer->get_data(['studentsubmissions', $user1->id, 'attempt 1',
     435                  'Feedback comments'])->commenttext);
     436          $this->assertStringContainsString($teachercommenttext2, $writer->get_data(['studentsubmissions', $user2->id, 'attempt 1',
     437                  'Feedback comments'])->commenttext);
     438          $this->assertStringContainsString($teachercommenttext3, $writer->get_data(['studentsubmissions', $user2->id, 'attempt 2',
     439                  'Feedback comments'])->commenttext);
     440      }
     441  
     442      /**
     443       * A test for deleting all user data for a given context.
     444       */
     445      public function test_delete_data_for_all_users_in_context() {
     446          global $DB;
     447          $this->resetAfterTest();
     448          $course = $this->getDataGenerator()->create_course();
     449  
     450          $user1 = $this->getDataGenerator()->create_user();
     451          $user2 = $this->getDataGenerator()->create_user();
     452          $teacher = $this->getDataGenerator()->create_user();
     453          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
     454          $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
     455          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
     456          $assign = $this->create_instance([
     457                  'course' => $course,
     458                  'name' => 'Assign 1',
     459                  'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
     460                  'maxattempts' => 3,
     461                  'assignsubmission_onlinetext_enabled' => true,
     462                  'assignfeedback_comments_enabled' => true
     463              ]);
     464  
     465          $context = $assign->get_context();
     466  
     467          // Create and grade some submissions from the students.
     468          $submissiontext = 'My first submission';
     469          $submission = $this->create_submission($assign, $user1, $submissiontext);
     470  
     471          $this->setUser($teacher);
     472  
     473          // Overrides for both students.
     474          $overridedata = new \stdClass();
     475          $overridedata->assignid = $assign->get_instance()->id;
     476          $overridedata->userid = $user1->id;
     477          $overridedata->duedate = time();
     478          $DB->insert_record('assign_overrides', $overridedata);
     479          $overridedata->userid = $user2->id;
     480          $DB->insert_record('assign_overrides', $overridedata);
     481          assign_update_events($assign);
     482  
     483          $grade1 = '54.00';
     484          $teachercommenttext = 'Comment on user 1 attempt 1.';
     485          $data = new \stdClass();
     486          $data->attemptnumber = 0;
     487          $data->grade = $grade1;
     488          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
     489  
     490          // Give the submission a grade.
     491          $assign->save_grade($user1->id, $data);
     492  
     493          // Create and grade some submissions from the students.
     494          $submissiontext2 = 'My first submission for user 2';
     495          $submission = $this->create_submission($assign, $user2, $submissiontext2);
     496  
     497          $this->setUser($teacher);
     498  
     499          $grade2 = '56.00';
     500          $teachercommenttext2 = 'Comment on user 2 first attempt.';
     501          $data = new \stdClass();
     502          $data->attemptnumber = 0;
     503          $data->grade = $grade2;
     504          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext2, 'format' => FORMAT_MOODLE];
     505  
     506          // Give the submission a grade.
     507          $assign->save_grade($user2->id, $data);
     508  
     509          // Create and grade some submissions from the students.
     510          $submissiontext3 = 'My second submission for user 2';
     511          $submission = $this->create_submission($assign, $user2, $submissiontext3, 1);
     512  
     513          $this->setUser($teacher);
     514  
     515          $grade3 = '83.00';
     516          $teachercommenttext3 = 'Comment on user 2 another attempt.';
     517          $data = new \stdClass();
     518          $data->attemptnumber = 1;
     519          $data->grade = $grade3;
     520          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext3, 'format' => FORMAT_MOODLE];
     521  
     522          // Give the submission a grade.
     523          $assign->save_grade($user2->id, $data);
     524  
     525          // Delete all user data for this assignment.
     526          provider::delete_data_for_all_users_in_context($context);
     527  
     528          // Check all relevant tables.
     529          $records = $DB->get_records('assign_submission');
     530          $this->assertEmpty($records);
     531          $records = $DB->get_records('assign_grades');
     532          $this->assertEmpty($records);
     533          $records = $DB->get_records('assignsubmission_onlinetext');
     534          $this->assertEmpty($records);
     535          $records = $DB->get_records('assignfeedback_comments');
     536          $this->assertEmpty($records);
     537  
     538          // Check that overrides and the calendar events are deleted.
     539          $records = $DB->get_records('event');
     540          $this->assertEmpty($records);
     541          $records = $DB->get_records('assign_overrides');
     542          $this->assertEmpty($records);
     543      }
     544  
     545      /**
     546       * A test for deleting all user data for one user.
     547       */
     548      public function test_delete_data_for_user() {
     549          global $DB;
     550          $this->resetAfterTest();
     551          $course = $this->getDataGenerator()->create_course();
     552  
     553          $coursecontext = \context_course::instance($course->id);
     554  
     555          $user1 = $this->getDataGenerator()->create_user();
     556          $user2 = $this->getDataGenerator()->create_user();
     557          $teacher = $this->getDataGenerator()->create_user();
     558          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
     559          $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
     560          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
     561          $assign = $this->create_instance([
     562                  'course' => $course,
     563                  'name' => 'Assign 1',
     564                  'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
     565                  'maxattempts' => 3,
     566                  'assignsubmission_onlinetext_enabled' => true,
     567                  'assignfeedback_comments_enabled' => true
     568              ]);
     569  
     570          $context = $assign->get_context();
     571  
     572          // Create and grade some submissions from the students.
     573          $submissiontext = 'My first submission';
     574          $submission1 = $this->create_submission($assign, $user1, $submissiontext);
     575  
     576          $this->setUser($teacher);
     577  
     578          // Overrides for both students.
     579          $overridedata = new \stdClass();
     580          $overridedata->assignid = $assign->get_instance()->id;
     581          $overridedata->userid = $user1->id;
     582          $overridedata->duedate = time();
     583          $DB->insert_record('assign_overrides', $overridedata);
     584          $overridedata->userid = $user2->id;
     585          $DB->insert_record('assign_overrides', $overridedata);
     586          assign_update_events($assign);
     587  
     588          $grade1 = '54.00';
     589          $teachercommenttext = 'Comment on user 1 attempt 1.';
     590          $data = new \stdClass();
     591          $data->attemptnumber = 0;
     592          $data->grade = $grade1;
     593          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
     594  
     595          // Give the submission a grade.
     596          $assign->save_grade($user1->id, $data);
     597  
     598          // Create and grade some submissions from the students.
     599          $submissiontext2 = 'My first submission for user 2';
     600          $submission2 = $this->create_submission($assign, $user2, $submissiontext2);
     601  
     602          $this->setUser($teacher);
     603  
     604          $grade2 = '56.00';
     605          $teachercommenttext2 = 'Comment on user 2 first attempt.';
     606          $data = new \stdClass();
     607          $data->attemptnumber = 0;
     608          $data->grade = $grade2;
     609          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext2, 'format' => FORMAT_MOODLE];
     610  
     611          // Give the submission a grade.
     612          $assign->save_grade($user2->id, $data);
     613  
     614          // Create and grade some submissions from the students.
     615          $submissiontext3 = 'My second submission for user 2';
     616          $submission3 = $this->create_submission($assign, $user2, $submissiontext3, 1);
     617  
     618          $this->setUser($teacher);
     619  
     620          $grade3 = '83.00';
     621          $teachercommenttext3 = 'Comment on user 2 another attempt.';
     622          $data = new \stdClass();
     623          $data->attemptnumber = 1;
     624          $data->grade = $grade3;
     625          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext3, 'format' => FORMAT_MOODLE];
     626  
     627          // Give the submission a grade.
     628          $assign->save_grade($user2->id, $data);
     629  
     630          // Delete user 2's data.
     631          $approvedlist = new approved_contextlist($user2, 'mod_assign', [$context->id, $coursecontext->id]);
     632          provider::delete_data_for_user($approvedlist);
     633  
     634          // Check all relevant tables.
     635          $records = $DB->get_records('assign_submission');
     636          foreach ($records as $record) {
     637              $this->assertEquals($user1->id, $record->userid);
     638              $this->assertNotEquals($user2->id, $record->userid);
     639          }
     640          $records = $DB->get_records('assign_grades');
     641          foreach ($records as $record) {
     642              $this->assertEquals($user1->id, $record->userid);
     643              $this->assertNotEquals($user2->id, $record->userid);
     644          }
     645          $records = $DB->get_records('assignsubmission_onlinetext');
     646          $this->assertCount(1, $records);
     647          $record = array_shift($records);
     648          // The only submission is for user 1.
     649          $this->assertEquals($submission1->id, $record->submission);
     650          $records = $DB->get_records('assignfeedback_comments');
     651          $this->assertCount(1, $records);
     652          $record = array_shift($records);
     653          // The only record is the feedback comment for user 1.
     654          $this->assertEquals($teachercommenttext, $record->commenttext);
     655  
     656          // Check calendar events as well as assign overrides.
     657          $records = $DB->get_records('event');
     658          $this->assertCount(1, $records);
     659          $record = array_shift($records);
     660          // The remaining event should be for user 1.
     661          $this->assertEquals($user1->id, $record->userid);
     662          // Now for assign_overrides
     663          $records = $DB->get_records('assign_overrides');
     664          $this->assertCount(1, $records);
     665          $record = array_shift($records);
     666          // The remaining event should be for user 1.
     667          $this->assertEquals($user1->id, $record->userid);
     668      }
     669  
     670      /**
     671       * A test for deleting all user data for a bunch of users.
     672       */
     673      public function test_delete_data_for_users() {
     674          global $DB;
     675  
     676          $this->resetAfterTest();
     677  
     678          $course = $this->getDataGenerator()->create_course();
     679  
     680          // Only made a comment on a submission.
     681          $user1 = $this->getDataGenerator()->create_user();
     682          // User 2 only has information about an activity override.
     683          $user2 = $this->getDataGenerator()->create_user();
     684          // User 3 made a submission.
     685          $user3 = $this->getDataGenerator()->create_user();
     686          // User 4 makes a submission and it is marked by the teacher.
     687          $user4 = $this->getDataGenerator()->create_user();
     688          // Grading and providing feedback as a teacher.
     689          $user5 = $this->getDataGenerator()->create_user();
     690          // This user has entries in assignment 2 and should not have their data deleted.
     691          $user6 = $this->getDataGenerator()->create_user();
     692  
     693          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
     694          $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
     695          $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student');
     696          $this->getDataGenerator()->enrol_user($user4->id, $course->id, 'student');
     697          $this->getDataGenerator()->enrol_user($user5->id, $course->id, 'editingteacher');
     698          $this->getDataGenerator()->enrol_user($user6->id, $course->id, 'student');
     699  
     700          $assign1 = $this->create_instance(['course' => $course,
     701                  'assignsubmission_onlinetext_enabled' => true,
     702                  'assignfeedback_comments_enabled' => true]);
     703          $assign2 = $this->create_instance(['course' => $course,
     704                  'assignsubmission_onlinetext_enabled' => true,
     705                  'assignfeedback_comments_enabled' => true]);
     706  
     707          $context = $assign1->get_context();
     708  
     709          // Jam an entry in the comments table for user 1.
     710          $comment = (object) [
     711              'contextid' => $context->id,
     712              'component' => 'assignsubmission_comments',
     713              'commentarea' => 'submission_comments',
     714              'itemid' => 5,
     715              'content' => 'A comment by user 1',
     716              'format' => 0,
     717              'userid' => $user1->id,
     718              'timecreated' => time()
     719          ];
     720          $DB->insert_record('comments', $comment);
     721  
     722          $this->setUser($user5); // Set the user to the teacher.
     723  
     724          $overridedata = new \stdClass();
     725          $overridedata->assignid = $assign1->get_instance()->id;
     726          $overridedata->userid = $user2->id;
     727          $overridedata->duedate = time();
     728          $overridedata->allowsubmissionsfromdate = time();
     729          $overridedata->cutoffdate = time();
     730          $DB->insert_record('assign_overrides', $overridedata);
     731  
     732          $submissiontext = 'My first submission';
     733          $submission = $this->create_submission($assign1, $user3, $submissiontext);
     734  
     735          $submissiontext = 'My first submission';
     736          $submission = $this->create_submission($assign1, $user4, $submissiontext);
     737  
     738          $submissiontext = 'My first submission';
     739          $submission = $this->create_submission($assign2, $user6, $submissiontext);
     740  
     741          $this->setUser($user5);
     742  
     743          $grade = '72.00';
     744          $teachercommenttext = 'This is better. Thanks.';
     745          $data = new \stdClass();
     746          $data->attemptnumber = 1;
     747          $data->grade = $grade;
     748          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
     749  
     750          // Give the submission a grade.
     751          $assign1->save_grade($user4->id, $data);
     752  
     753          $this->setUser($user5);
     754  
     755          $grade = '81.00';
     756          $teachercommenttext = 'This is nice.';
     757          $data = new \stdClass();
     758          $data->attemptnumber = 1;
     759          $data->grade = $grade;
     760          $data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
     761  
     762          // Give the submission a grade.
     763          $assign2->save_grade($user6->id, $data);
     764  
     765          // Check data is in place.
     766          $data = $DB->get_records('assign_submission');
     767          // We should have one entry for user 3 and two entries each for user 4 and 6.
     768          $this->assertCount(5, $data);
     769          $usercounts = [
     770              $user3->id => 0,
     771              $user4->id => 0,
     772              $user6->id => 0
     773          ];
     774          foreach ($data as $datum) {
     775              $usercounts[$datum->userid]++;
     776          }
     777          $this->assertEquals(1, $usercounts[$user3->id]);
     778          $this->assertEquals(2, $usercounts[$user4->id]);
     779          $this->assertEquals(2, $usercounts[$user6->id]);
     780  
     781          $data = $DB->get_records('assign_grades');
     782          // Two entries in assign_grades, one for each grade given.
     783          $this->assertCount(2, $data);
     784  
     785          $data = $DB->get_records('assign_overrides');
     786          $this->assertCount(1, $data);
     787  
     788          $data = $DB->get_records('comments');
     789          $this->assertCount(1, $data);
     790  
     791          $userlist = new \core_privacy\local\request\approved_userlist($context, 'assign', [$user1->id, $user2->id]);
     792          provider::delete_data_for_users($userlist);
     793  
     794          $data = $DB->get_records('assign_overrides');
     795          $this->assertEmpty($data);
     796  
     797          $data = $DB->get_records('comments');
     798          $this->assertEmpty($data);
     799  
     800          $data = $DB->get_records('assign_submission');
     801          // No change here.
     802          $this->assertCount(5, $data);
     803  
     804          $userlist = new \core_privacy\local\request\approved_userlist($context, 'assign', [$user3->id, $user5->id]);
     805          provider::delete_data_for_users($userlist);
     806  
     807          $data = $DB->get_records('assign_submission');
     808          // Only the record for user 3 has been deleted.
     809          $this->assertCount(4, $data);
     810  
     811          $data = $DB->get_records('assign_grades');
     812          // Grades should be unchanged.
     813          $this->assertCount(2, $data);
     814      }
     815  }