You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

583 lines
26 KiB

<?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 core_notes implementation of the privacy API.
*
* @package core_notes
* @category test
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . "/notes/lib.php");
use \core_notes\privacy\provider;
use \core_privacy\local\request\writer;
use \core_privacy\local\request\approved_contextlist;
use \core_privacy\local\request\approved_userlist;
/**
* Unit tests for the core_notes implementation of the privacy API.
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_notes_privacy_testcase extends \core_privacy\tests\provider_testcase {
/**
* Test for provider::get_contexts_for_userid().
*/
public function test_get_contexts_for_userid() {
global $DB;
// Test setup.
$this->resetAfterTest(true);
$this->setAdminUser();
set_config('enablenotes', true);
$teacher1 = $this->getDataGenerator()->create_user();
$this->setUser($teacher1);
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
$student = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Create Courses, then enrol a teacher and a student.
$nocourses = 5;
$courses = [];
$coursecontextids = [];
for ($c = 1; $c <= $nocourses; $c++) {
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
role_assign($teacherrole->id, $teacher1->id, $coursecontext->id);
role_assign($studentrole->id, $student->id, $coursecontext->id);
// Only create private user notes (i.e. NOTES_STATE_DRAFT) for student in Course 1, 2, 3 written by the teacher.
if ($c <= 3) {
$this->help_create_user_note(
$student->id,
NOTES_STATE_DRAFT,
$course->id,
"Test private user note about the student in Course $c by the teacher"
);
}
$courses[$c] = $course;
$coursecontextids[] = $coursecontext->id;
}
// Test Teacher 1's contexts equals 3 because only 3 user notes were added for Course 1, 2, and 3.
// Course 4 and 5 does not have any notes associated with it, so the contexts should not be returned.
$contexts = provider::get_contexts_for_userid($teacher1->id);
$this->assertCount(3, $contexts->get_contextids());
// Test the Student's contexts is 0 because the notes written by the teacher are private.
$contexts = provider::get_contexts_for_userid($student->id);
$this->assertCount(0, $contexts->get_contextids());
// Add a public user note (i.e. NOTES_STATE_PUBLIC) written by the Teacher about the Student in Course 4.
$course = $courses[4];
$this->help_create_user_note(
$student->id,
NOTES_STATE_PUBLIC,
$course->id,
"Test public user note about the student in Course 4 by the teacher"
);
// Test Teacher 1's contexts equals 4 after adding a public note about a student in Course 4.
$contexts = provider::get_contexts_for_userid($teacher1->id);
$this->assertCount(4, $contexts->get_contextids());
// Test the Student's contexts is 1 for Course 4 because there is a public note written by the teacher.
$contexts = provider::get_contexts_for_userid($student->id);
$this->assertCount(1, $contexts->get_contextids());
// Add a site-wide user note (i.e. NOTES_STATE_SITE) written by the Teacher 1 about the Student in Course 3.
$course = $courses[3];
$this->help_create_user_note(
$student->id,
NOTES_STATE_SITE,
$course->id,
"Test site-wide user note about the student in Course 3 by the teacher"
);
// Test the Student's contexts is 2 for Courses 3, 4 because there is a public and site-wide note written by the Teacher.
$contexts = provider::get_contexts_for_userid($student->id);
$this->assertCount(2, $contexts->get_contextids());
// Add a site-wide user note for the Teacher 1 by another Teacher 2 in Course 5.
$teacher2 = $this->getDataGenerator()->create_user();
$this->setUser($teacher2);
$course = $courses[5];
$this->help_create_user_note(
$teacher1->id,
NOTES_STATE_SITE,
$course->id,
"Test site-wide user note about the teacher in Course 5 by another teacher"
);
// Test Teacher 1's contexts equals 5 after adding the note from another teacher.
$contextlist = provider::get_contexts_for_userid($teacher1->id);
$this->assertCount(5, $contextlist->get_contextids());
// Test Teacher 1's contexts match the contexts of the Courses associated with notes created.
$this->assertEmpty(array_diff($coursecontextids, $contextlist->get_contextids()));
}
/**
* Test for provider::export_user_data().
*/
public function test_export_user_data() {
global $DB;
// Test setup.
$this->resetAfterTest(true);
$this->setAdminUser();
set_config('enablenotes', true);
$teacher1 = $this->getDataGenerator()->create_user();
$this->setUser($teacher1);
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
$nocourses = 5;
$nostudents = 2;
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$courses = [];
$coursecontextids = [];
for ($c = 1; $c <= $nocourses; $c++) {
// Create a Course, then enrol a teacher and enrol 2 students.
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
role_assign($teacherrole->id, $teacher1->id, $coursecontext->id);
// Only create public user notes (i.e. NOTES_STATE_PUBLIC) for students in Course 1, 2, 3 written by the teacher.
if ($c <= 3) {
for ($s = 0; $s < $nostudents; $s++) {
$student = $this->getDataGenerator()->create_user();
role_assign($studentrole->id, $student->id, $coursecontext->id);
// Create test public user note data written for students by the teacher.
$this->help_create_user_note(
$student->id,
NOTES_STATE_PUBLIC,
$course->id,
"Test public user note for student $s in Course $c by the teacher"
);
}
// Store the Course context for those which have test notes added for verification.
$coursecontextids[] = $coursecontext->id;
}
$courses[$c] = $course;
}
// Add a site-wide user note for Teacher 1 by another Teacher 2 in Course 4.
$teacher2 = $this->getDataGenerator()->create_user();
$this->setUser($teacher2);
$course = $courses[4];
$this->help_create_user_note(
$teacher1->id,
NOTES_STATE_SITE,
$course->id,
"Test site-wide user note about the teacher in Course 4 by another teacher"
);
// Store the Course context for those which have test notes added for verification.
$coursecontextids[] = context_course::instance($course->id)->id;
// Add a private user note for Teacher 1 by another Teacher 2 in Course 5.
$course = $courses[5];
$this->help_create_user_note(
$teacher1->id,
NOTES_STATE_DRAFT,
$course->id,
"Test private user note about the teacher in Course 5 by another teacher"
);
// Test the number of contexts returned matches the Course contexts created with notes.
$contextlist = provider::get_contexts_for_userid($teacher1->id);
$this->assertEmpty(array_diff($coursecontextids, $contextlist->get_contextids()));
$approvedcontextlist = new approved_contextlist($teacher1, 'core_notes', $contextlist->get_contextids());
// Retrieve User notes created by the teacher.
provider::export_user_data($approvedcontextlist);
// Test the core_notes data is exported at the Course context level and has content.
foreach ($contextlist as $context) {
$this->assertEquals(CONTEXT_COURSE, $context->contextlevel);
$writer = writer::with_context($context);
$this->assertTrue($writer->has_any_data());
}
}
/**
* Test for provider::delete_data_for_all_users_in_context().
*/
public function test_delete_data_for_all_users_in_context() {
global $DB;
// Test setup.
$this->resetAfterTest(true);
$this->setAdminUser();
set_config('enablenotes', true);
$teacher = $this->getDataGenerator()->create_user();
$this->setUser($teacher);
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
$nocourses = 2;
$nostudents = 5;
$nonotes = 7;
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$n = 0;
for ($c = 0; $c < $nocourses; $c++) {
// Create a Course, then enrol a teacher and enrol 2 students.
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
role_assign($teacherrole->id, $teacher->id, $coursecontext->id);
for ($s = 0; $s < $nostudents; $s++) {
if ($n < $nonotes) {
$student = $this->getDataGenerator()->create_user();
role_assign($studentrole->id, $student->id, $coursecontext->id);
// Create test note data.
$this->help_create_user_note(
$student->id,
NOTES_STATE_PUBLIC,
$course->id,
"Test user note for student $s in Course $c"
);
}
$n++;
}
}
// Test the number of contexts returned equals the number of Courses created with user notes for its students.
$contextlist = provider::get_contexts_for_userid($teacher->id);
$this->assertCount($nocourses, $contextlist->get_contextids());
// Test the created user note records in mdl_post table matches the test number of user notes specified.
$notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]);
$this->assertCount($nonotes, $notes);
// Delete all user note records in mdl_post table by the specified Course context.
foreach ($contextlist->get_contexts() as $context) {
provider::delete_data_for_all_users_in_context($context);
}
// Test the core_note records in mdl_post table is equals zero.
$notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]);
$this->assertCount(0, $notes);
}
/**
* Test for provider::delete_data_for_user().
*/
public function test_delete_data_for_user() {
global $DB;
// Test setup.
$this->resetAfterTest(true);
$this->setAdminUser();
set_config('enablenotes', true);
$teacher = $this->getDataGenerator()->create_user();
$this->setUser($teacher);
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
$nocourses = 2;
$nostudents = 5;
$nonotes = 7;
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$n = 0;
for ($c = 0; $c < $nocourses; $c++) {
// Create a Course, then enrol a teacher and enrol 2 students.
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
role_assign($teacherrole->id, $teacher->id, $coursecontext->id);
for ($s = 0; $s < $nostudents; $s++) {
if ($n < $nonotes) {
$student = $this->getDataGenerator()->create_user();
role_assign($studentrole->id, $student->id, $coursecontext->id);
// Create test note data.
$this->help_create_user_note(
$student->id,
NOTES_STATE_PUBLIC,
$course->id,
"Test user note for student $s in Course $c"
);
}
$n++;
}
}
// Test the number of contexts returned equals the number of Courses created with user notes for its students.
$contextlist = provider::get_contexts_for_userid($teacher->id);
$this->assertCount($nocourses, $contextlist->get_contextids());
// Test the created user note records in mdl_post table matches the test number of user notes specified.
$notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]);
$this->assertCount($nonotes, $notes);
// Delete all user note records in mdl_post table created by the specified teacher.
$approvedcontextlist = new approved_contextlist($teacher, 'core_notes', $contextlist->get_contextids());
provider::delete_data_for_user($approvedcontextlist);
// Test the core_note records in mdl_post table is equals zero.
$notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]);
$this->assertCount(0, $notes);
}
/**
* Test that only users within a course context are fetched.
*/
public function test_get_users_in_context() {
global $DB;
$this->resetAfterTest(true);
$component = 'core_notes';
// Test setup.
$this->setAdminUser();
set_config('enablenotes', true);
// Create a teacher.
$teacher1 = $this->getDataGenerator()->create_user();
$this->setUser($teacher1);
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
// Create a student.
$student = $this->getDataGenerator()->create_user();
// Create student2.
$student2 = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Create courses, then enrol a teacher and a student.
$nocourses = 3;
for ($c = 1; $c <= $nocourses; $c++) {
${'course' . $c} = $this->getDataGenerator()->create_course();
${'coursecontext' . $c} = context_course::instance(${'course' . $c}->id);
role_assign($teacherrole->id, $teacher1->id, ${'coursecontext' . $c}->id);
role_assign($studentrole->id, $student->id, ${'coursecontext' . $c}->id);
role_assign($studentrole->id, $student2->id, ${'coursecontext' . $c}->id);
}
// The list of users in coursecontext1 should be empty (related data still have not been created).
$userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(0, $userlist1);
// The list of users in coursecontext2 should be empty (related data still have not been created).
$userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(0, $userlist2);
// The list of users in coursecontext3 should be empty (related data still have not been created).
$userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component);
provider::get_users_in_context($userlist3);
$this->assertCount(0, $userlist3);
// Create private user notes (i.e. NOTES_STATE_DRAFT) for student in course1 and course2 written by the teacher.
$this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course1->id,
"Test private user note about the student in Course 1 by the teacher");
$this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course2->id,
"Test private user note about the student in Course 2 by the teacher");
// The list of users in coursecontext1 should return one user (teacher1).
provider::get_users_in_context($userlist1);
$this->assertCount(1, $userlist1);
$this->assertTrue(in_array($teacher1->id, $userlist1->get_userids()));
// The list of users in coursecontext2 should return one user (teacher1).
provider::get_users_in_context($userlist2);
$this->assertCount(1, $userlist2);
$this->assertTrue(in_array($teacher1->id, $userlist2->get_userids()));
// The list of users in coursecontext3 should not return any users.
provider::get_users_in_context($userlist3);
$this->assertCount(0, $userlist3);
// Create public user note (i.e. NOTES_STATE_PUBLIC) for student in course3 written by the teacher.
$this->help_create_user_note($student->id, NOTES_STATE_PUBLIC, $course3->id,
"Test public user note about the student in Course 3 by the teacher");
// The list of users in coursecontext3 should return 2 users (teacher and student).
provider::get_users_in_context($userlist3);
$this->assertCount(2, $userlist3);
$this->assertTrue(in_array($teacher1->id, $userlist3->get_userids()));
$this->assertTrue(in_array($student->id, $userlist3->get_userids()));
// Create site user note (i.e. NOTES_STATE_SITE) for student2 in course3 written by the teacher.
$this->help_create_user_note($student2->id, NOTES_STATE_SITE, $course3->id,
"Test site-wide user note about student2 in Course 3 by the teacher"
);
// The list of users in coursecontext3 should return 3 users (teacher, student and student2).
provider::get_users_in_context($userlist3);
$this->assertCount(3, $userlist3);
$this->assertTrue(in_array($teacher1->id, $userlist3->get_userids()));
$this->assertTrue(in_array($student->id, $userlist3->get_userids()));
$this->assertTrue(in_array($student2->id, $userlist3->get_userids()));
// The list of users should not return any users in a different context than course context.
$contextsystem = context_system::instance();
$userlist4 = new \core_privacy\local\request\userlist($contextsystem, $component);
provider::get_users_in_context($userlist4);
$this->assertCount(0, $userlist4);
}
/**
* Test that data for users in approved userlist is deleted.
*/
public function test_delete_data_for_users() {
global $DB;
$this->resetAfterTest(true);
$component = 'core_notes';
// Test setup.
$this->setAdminUser();
set_config('enablenotes', true);
// Create a teacher.
$teacher1 = $this->getDataGenerator()->create_user();
$this->setUser($teacher1);
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
// Create a student.
$student = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Create Courses, then enrol a teacher and a student.
$nocourses = 3;
for ($c = 1; $c <= $nocourses; $c++) {
${'course' . $c} = $this->getDataGenerator()->create_course();
${'coursecontext' . $c} = context_course::instance(${'course' . $c}->id);
role_assign($teacherrole->id, $teacher1->id, ${'coursecontext' . $c}->id);
role_assign($studentrole->id, $student->id, ${'coursecontext' . $c}->id);
}
// Create private notes for student in the course1 and course2 written by the teacher.
$this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course1->id,
"Test private user note about the student in Course 1 by the teacher");
$this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course2->id,
"Test private user note about the student in Course 2 by the teacher");
// Create public notes for student in the course3 written by the teacher.
$this->help_create_user_note($student->id, NOTES_STATE_PUBLIC, $course3->id,
"Test public user note about the student in Course 3 by the teacher");
// The list of users in coursecontext1 should return one user (teacher1).
$userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(1, $userlist1);
$this->assertTrue(in_array($teacher1->id, $userlist1->get_userids()));
// The list of users in coursecontext2 should return one user (teacher1).
$userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(1, $userlist2);
$this->assertTrue(in_array($teacher1->id, $userlist2->get_userids()));
// The list of users in coursecontext3 should return two users (teacher1 and student).
$userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component);
provider::get_users_in_context($userlist3);
$this->assertCount(2, $userlist3);
$this->assertTrue(in_array($teacher1->id, $userlist3->get_userids()));
$this->assertTrue(in_array($student->id, $userlist3->get_userids()));
$approvedlist = new approved_userlist($coursecontext3, $component, [$student->id]);
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist);
// Re-fetch users in the coursecontext3.
$userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component);
// The user data in coursecontext3 should not be removed.
provider::get_users_in_context($userlist3);
$this->assertCount(2, $userlist3);
$this->assertTrue(in_array($teacher1->id, $userlist3->get_userids()));
$this->assertTrue(in_array($student->id, $userlist3->get_userids()));
$approvedlist = new approved_userlist($coursecontext3, $component, [$teacher1->id]);
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist);
// Re-fetch users in the coursecontext3.
$userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component);
// The user data in coursecontext3 should be removed.
provider::get_users_in_context($userlist3);
$this->assertCount(0, $userlist3);
// Re-fetch users in the coursecontext1.
$userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(1, $userlist1);
$approvedlist = new approved_userlist($coursecontext1, $component, [$student->id]);
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist);
// Re-fetch users in the coursecontext1.
$userlist3 = new \core_privacy\local\request\userlist($coursecontext1, $component);
// The user data in coursecontext1 should not be removed.
provider::get_users_in_context($userlist3);
$this->assertCount(1, $userlist3);
$this->assertTrue(in_array($teacher1->id, $userlist3->get_userids()));
$approvedlist = new approved_userlist($coursecontext1, $component, [$teacher1->id]);
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist);
// Re-fetch users in the coursecontext1.
$userlist3 = new \core_privacy\local\request\userlist($coursecontext1, $component);
// The user data in coursecontext1 should be removed.
provider::get_users_in_context($userlist3);
$this->assertCount(0, $userlist3);
// Re-fetch users in the coursecontext2.
$userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(1, $userlist2);
// The list of users should not return any users for contexts different than course context.
$systemcontext = context_system::instance();
$userlist4 = new \core_privacy\local\request\userlist($systemcontext, $component);
provider::get_users_in_context($userlist4);
$this->assertCount(0, $userlist4);
}
/**
* Helper function to create user notes for testing.
*
* @param int $userid The ID of the User associated with the note.
* @param string $state The publish status
* @param int $courseid The ID of the Course associated with the note.
* @param string $content The note content.
*/
protected function help_create_user_note($userid, $state, $courseid, $content) {
$note = (object) [
'userid' => $userid,
'publishstate' => $state,
'courseid' => $courseid,
'content' => $content,
];
note_save($note);
}
}