Differences Between: [Versions 311 and 403] [Versions 400 and 403] [Versions 401 and 403]
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 * Unit tests for the core_notes implementation of the privacy API. 19 * 20 * @package core_notes 21 * @category test 22 * @copyright 2018 Zig Tan <zig@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 namespace core_notes\privacy; 26 27 defined('MOODLE_INTERNAL') || die(); 28 global $CFG; 29 30 require_once($CFG->dirroot . "/notes/lib.php"); 31 32 use core_notes\privacy\provider; 33 use core_privacy\local\request\writer; 34 use core_privacy\local\request\approved_contextlist; 35 use core_privacy\local\request\approved_userlist; 36 37 /** 38 * Unit tests for the core_notes implementation of the privacy API. 39 * 40 * @copyright 2018 Zig Tan <zig@moodle.com> 41 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 42 */ 43 class provider_test extends \core_privacy\tests\provider_testcase { 44 45 /** 46 * Test for provider::get_contexts_for_userid(). 47 */ 48 public function test_get_contexts_for_userid() { 49 global $DB; 50 51 // Test setup. 52 $this->resetAfterTest(true); 53 $this->setAdminUser(); 54 set_config('enablenotes', true); 55 56 $teacher1 = $this->getDataGenerator()->create_user(); 57 $this->setUser($teacher1); 58 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 59 60 $student = $this->getDataGenerator()->create_user(); 61 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 62 63 // Create Courses, then enrol a teacher and a student. 64 $nocourses = 5; 65 $courses = []; 66 $coursecontextids = []; 67 for ($c = 1; $c <= $nocourses; $c++) { 68 $course = $this->getDataGenerator()->create_course(); 69 $coursecontext = \context_course::instance($course->id); 70 71 role_assign($teacherrole->id, $teacher1->id, $coursecontext->id); 72 role_assign($studentrole->id, $student->id, $coursecontext->id); 73 74 // Only create private user notes (i.e. NOTES_STATE_DRAFT) for student in Course 1, 2, 3 written by the teacher. 75 if ($c <= 3) { 76 $this->help_create_user_note( 77 $student->id, 78 NOTES_STATE_DRAFT, 79 $course->id, 80 "Test private user note about the student in Course $c by the teacher" 81 ); 82 } 83 84 $courses[$c] = $course; 85 $coursecontextids[] = $coursecontext->id; 86 } 87 88 // Test Teacher 1's contexts equals 3 because only 3 user notes were added for Course 1, 2, and 3. 89 // Course 4 and 5 does not have any notes associated with it, so the contexts should not be returned. 90 $contexts = provider::get_contexts_for_userid($teacher1->id); 91 $this->assertCount(3, $contexts->get_contextids()); 92 93 // Test the Student's contexts is 0 because the notes written by the teacher are private. 94 $contexts = provider::get_contexts_for_userid($student->id); 95 $this->assertCount(0, $contexts->get_contextids()); 96 97 // Add a public user note (i.e. NOTES_STATE_PUBLIC) written by the Teacher about the Student in Course 4. 98 $course = $courses[4]; 99 $this->help_create_user_note( 100 $student->id, 101 NOTES_STATE_PUBLIC, 102 $course->id, 103 "Test public user note about the student in Course 4 by the teacher" 104 ); 105 106 // Test Teacher 1's contexts equals 4 after adding a public note about a student in Course 4. 107 $contexts = provider::get_contexts_for_userid($teacher1->id); 108 $this->assertCount(4, $contexts->get_contextids()); 109 110 // Test the Student's contexts is 1 for Course 4 because there is a public note written by the teacher. 111 $contexts = provider::get_contexts_for_userid($student->id); 112 $this->assertCount(1, $contexts->get_contextids()); 113 114 // Add a site-wide user note (i.e. NOTES_STATE_SITE) written by the Teacher 1 about the Student in Course 3. 115 $course = $courses[3]; 116 $this->help_create_user_note( 117 $student->id, 118 NOTES_STATE_SITE, 119 $course->id, 120 "Test site-wide user note about the student in Course 3 by the teacher" 121 ); 122 123 // Test the Student's contexts is 2 for Courses 3, 4 because there is a public and site-wide note written by the Teacher. 124 $contexts = provider::get_contexts_for_userid($student->id); 125 $this->assertCount(2, $contexts->get_contextids()); 126 127 // Add a site-wide user note for the Teacher 1 by another Teacher 2 in Course 5. 128 $teacher2 = $this->getDataGenerator()->create_user(); 129 $this->setUser($teacher2); 130 131 $course = $courses[5]; 132 $this->help_create_user_note( 133 $teacher1->id, 134 NOTES_STATE_SITE, 135 $course->id, 136 "Test site-wide user note about the teacher in Course 5 by another teacher" 137 ); 138 139 // Test Teacher 1's contexts equals 5 after adding the note from another teacher. 140 $contextlist = provider::get_contexts_for_userid($teacher1->id); 141 $this->assertCount(5, $contextlist->get_contextids()); 142 143 // Test Teacher 1's contexts match the contexts of the Courses associated with notes created. 144 $this->assertEmpty(array_diff($coursecontextids, $contextlist->get_contextids())); 145 } 146 147 /** 148 * Test for provider::export_user_data(). 149 */ 150 public function test_export_user_data() { 151 global $DB; 152 153 // Test setup. 154 $this->resetAfterTest(true); 155 $this->setAdminUser(); 156 set_config('enablenotes', true); 157 158 $teacher1 = $this->getDataGenerator()->create_user(); 159 $this->setUser($teacher1); 160 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 161 162 $nocourses = 5; 163 $nostudents = 2; 164 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 165 166 $courses = []; 167 $coursecontextids = []; 168 for ($c = 1; $c <= $nocourses; $c++) { 169 // Create a Course, then enrol a teacher and enrol 2 students. 170 $course = $this->getDataGenerator()->create_course(); 171 $coursecontext = \context_course::instance($course->id); 172 173 role_assign($teacherrole->id, $teacher1->id, $coursecontext->id); 174 175 // Only create public user notes (i.e. NOTES_STATE_PUBLIC) for students in Course 1, 2, 3 written by the teacher. 176 if ($c <= 3) { 177 for ($s = 0; $s < $nostudents; $s++) { 178 $student = $this->getDataGenerator()->create_user(); 179 role_assign($studentrole->id, $student->id, $coursecontext->id); 180 181 // Create test public user note data written for students by the teacher. 182 $this->help_create_user_note( 183 $student->id, 184 NOTES_STATE_PUBLIC, 185 $course->id, 186 "Test public user note for student $s in Course $c by the teacher" 187 ); 188 } 189 // Store the Course context for those which have test notes added for verification. 190 $coursecontextids[] = $coursecontext->id; 191 } 192 193 $courses[$c] = $course; 194 } 195 196 // Add a site-wide user note for Teacher 1 by another Teacher 2 in Course 4. 197 $teacher2 = $this->getDataGenerator()->create_user(); 198 $this->setUser($teacher2); 199 200 $course = $courses[4]; 201 $this->help_create_user_note( 202 $teacher1->id, 203 NOTES_STATE_SITE, 204 $course->id, 205 "Test site-wide user note about the teacher in Course 4 by another teacher" 206 ); 207 // Store the Course context for those which have test notes added for verification. 208 $coursecontextids[] = \context_course::instance($course->id)->id; 209 210 // Add a private user note for Teacher 1 by another Teacher 2 in Course 5. 211 $course = $courses[5]; 212 $this->help_create_user_note( 213 $teacher1->id, 214 NOTES_STATE_DRAFT, 215 $course->id, 216 "Test private user note about the teacher in Course 5 by another teacher" 217 ); 218 219 // Test the number of contexts returned matches the Course contexts created with notes. 220 $contextlist = provider::get_contexts_for_userid($teacher1->id); 221 $this->assertEmpty(array_diff($coursecontextids, $contextlist->get_contextids())); 222 223 $approvedcontextlist = new approved_contextlist($teacher1, 'core_notes', $contextlist->get_contextids()); 224 225 // Retrieve User notes created by the teacher. 226 provider::export_user_data($approvedcontextlist); 227 228 // Test the core_notes data is exported at the Course context level and has content. 229 foreach ($contextlist as $context) { 230 $this->assertEquals(CONTEXT_COURSE, $context->contextlevel); 231 232 /** @var \core_privacy\tests\request\content_writer $writer */ 233 $writer = writer::with_context($context); 234 $this->assertTrue($writer->has_any_data()); 235 } 236 } 237 238 /** 239 * Test for provider::delete_data_for_all_users_in_context(). 240 */ 241 public function test_delete_data_for_all_users_in_context() { 242 global $DB; 243 244 // Test setup. 245 $this->resetAfterTest(true); 246 $this->setAdminUser(); 247 set_config('enablenotes', true); 248 249 $teacher = $this->getDataGenerator()->create_user(); 250 $this->setUser($teacher); 251 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 252 253 $nocourses = 2; 254 $nostudents = 5; 255 $nonotes = 7; 256 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 257 258 $n = 0; 259 for ($c = 0; $c < $nocourses; $c++) { 260 // Create a Course, then enrol a teacher and enrol 2 students. 261 $course = $this->getDataGenerator()->create_course(); 262 $coursecontext = \context_course::instance($course->id); 263 264 role_assign($teacherrole->id, $teacher->id, $coursecontext->id); 265 266 for ($s = 0; $s < $nostudents; $s++) { 267 if ($n < $nonotes) { 268 $student = $this->getDataGenerator()->create_user(); 269 role_assign($studentrole->id, $student->id, $coursecontext->id); 270 271 // Create test note data. 272 $this->help_create_user_note( 273 $student->id, 274 NOTES_STATE_PUBLIC, 275 $course->id, 276 "Test user note for student $s in Course $c" 277 ); 278 } 279 $n++; 280 } 281 } 282 283 // Test the number of contexts returned equals the number of Courses created with user notes for its students. 284 $contextlist = provider::get_contexts_for_userid($teacher->id); 285 $this->assertCount($nocourses, $contextlist->get_contextids()); 286 287 // Test the created user note records in mdl_post table matches the test number of user notes specified. 288 $notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]); 289 $this->assertCount($nonotes, $notes); 290 291 // Delete all user note records in mdl_post table by the specified Course context. 292 foreach ($contextlist->get_contexts() as $context) { 293 provider::delete_data_for_all_users_in_context($context); 294 } 295 296 // Test the core_note records in mdl_post table is equals zero. 297 $notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]); 298 $this->assertCount(0, $notes); 299 } 300 301 /** 302 * Test for provider::delete_data_for_user(). 303 */ 304 public function test_delete_data_for_user() { 305 global $DB; 306 307 // Test setup. 308 $this->resetAfterTest(true); 309 $this->setAdminUser(); 310 set_config('enablenotes', true); 311 312 $teacher = $this->getDataGenerator()->create_user(); 313 $this->setUser($teacher); 314 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 315 316 $nocourses = 2; 317 $nostudents = 5; 318 $nonotes = 7; 319 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 320 321 $n = 0; 322 for ($c = 0; $c < $nocourses; $c++) { 323 // Create a Course, then enrol a teacher and enrol 2 students. 324 $course = $this->getDataGenerator()->create_course(); 325 $coursecontext = \context_course::instance($course->id); 326 327 role_assign($teacherrole->id, $teacher->id, $coursecontext->id); 328 329 for ($s = 0; $s < $nostudents; $s++) { 330 if ($n < $nonotes) { 331 $student = $this->getDataGenerator()->create_user(); 332 role_assign($studentrole->id, $student->id, $coursecontext->id); 333 334 // Create test note data. 335 $this->help_create_user_note( 336 $student->id, 337 NOTES_STATE_PUBLIC, 338 $course->id, 339 "Test user note for student $s in Course $c" 340 ); 341 } 342 $n++; 343 } 344 } 345 346 // Test the number of contexts returned equals the number of Courses created with user notes for its students. 347 $contextlist = provider::get_contexts_for_userid($teacher->id); 348 $this->assertCount($nocourses, $contextlist->get_contextids()); 349 350 // Test the created user note records in mdl_post table matches the test number of user notes specified. 351 $notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]); 352 $this->assertCount($nonotes, $notes); 353 354 // Delete all user note records in mdl_post table created by the specified teacher. 355 $approvedcontextlist = new approved_contextlist($teacher, 'core_notes', $contextlist->get_contextids()); 356 provider::delete_data_for_user($approvedcontextlist); 357 358 // Test the core_note records in mdl_post table is equals zero. 359 $notes = $DB->get_records('post', ['module' => 'notes', 'usermodified' => $teacher->id]); 360 $this->assertCount(0, $notes); 361 } 362 363 /** 364 * Test that only users within a course context are fetched. 365 */ 366 public function test_get_users_in_context() { 367 global $DB; 368 369 $this->resetAfterTest(true); 370 371 $component = 'core_notes'; 372 // Test setup. 373 $this->setAdminUser(); 374 set_config('enablenotes', true); 375 // Create a teacher. 376 $teacher1 = $this->getDataGenerator()->create_user(); 377 $this->setUser($teacher1); 378 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 379 // Create a student. 380 $student = $this->getDataGenerator()->create_user(); 381 // Create student2. 382 $student2 = $this->getDataGenerator()->create_user(); 383 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 384 385 // Create courses, then enrol a teacher and a student. 386 $nocourses = 3; 387 for ($c = 1; $c <= $nocourses; $c++) { 388 ${'course' . $c} = $this->getDataGenerator()->create_course(); 389 ${'coursecontext' . $c} = \context_course::instance(${'course' . $c}->id); 390 391 role_assign($teacherrole->id, $teacher1->id, ${'coursecontext' . $c}->id); 392 role_assign($studentrole->id, $student->id, ${'coursecontext' . $c}->id); 393 role_assign($studentrole->id, $student2->id, ${'coursecontext' . $c}->id); 394 } 395 // The list of users in coursecontext1 should be empty (related data still have not been created). 396 $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); 397 provider::get_users_in_context($userlist1); 398 $this->assertCount(0, $userlist1); 399 // The list of users in coursecontext2 should be empty (related data still have not been created). 400 $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); 401 provider::get_users_in_context($userlist2); 402 $this->assertCount(0, $userlist2); 403 // The list of users in coursecontext3 should be empty (related data still have not been created). 404 $userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component); 405 provider::get_users_in_context($userlist3); 406 $this->assertCount(0, $userlist3); 407 408 // Create private user notes (i.e. NOTES_STATE_DRAFT) for student in course1 and course2 written by the teacher. 409 $this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course1->id, 410 "Test private user note about the student in Course 1 by the teacher"); 411 $this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course2->id, 412 "Test private user note about the student in Course 2 by the teacher"); 413 414 // The list of users in coursecontext1 should return one user (teacher1). 415 provider::get_users_in_context($userlist1); 416 $this->assertCount(1, $userlist1); 417 $this->assertTrue(in_array($teacher1->id, $userlist1->get_userids())); 418 // The list of users in coursecontext2 should return one user (teacher1). 419 provider::get_users_in_context($userlist2); 420 $this->assertCount(1, $userlist2); 421 $this->assertTrue(in_array($teacher1->id, $userlist2->get_userids())); 422 // The list of users in coursecontext3 should not return any users. 423 provider::get_users_in_context($userlist3); 424 $this->assertCount(0, $userlist3); 425 426 // Create public user note (i.e. NOTES_STATE_PUBLIC) for student in course3 written by the teacher. 427 $this->help_create_user_note($student->id, NOTES_STATE_PUBLIC, $course3->id, 428 "Test public user note about the student in Course 3 by the teacher"); 429 430 // The list of users in coursecontext3 should return 2 users (teacher and student). 431 provider::get_users_in_context($userlist3); 432 $this->assertCount(2, $userlist3); 433 $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); 434 $this->assertTrue(in_array($student->id, $userlist3->get_userids())); 435 436 // Create site user note (i.e. NOTES_STATE_SITE) for student2 in course3 written by the teacher. 437 $this->help_create_user_note($student2->id, NOTES_STATE_SITE, $course3->id, 438 "Test site-wide user note about student2 in Course 3 by the teacher" 439 ); 440 441 // The list of users in coursecontext3 should return 3 users (teacher, student and student2). 442 provider::get_users_in_context($userlist3); 443 $this->assertCount(3, $userlist3); 444 $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); 445 $this->assertTrue(in_array($student->id, $userlist3->get_userids())); 446 $this->assertTrue(in_array($student2->id, $userlist3->get_userids())); 447 448 // The list of users should not return any users in a different context than course context. 449 $contextsystem = \context_system::instance(); 450 $userlist4 = new \core_privacy\local\request\userlist($contextsystem, $component); 451 provider::get_users_in_context($userlist4); 452 $this->assertCount(0, $userlist4); 453 } 454 455 /** 456 * Test that data for users in approved userlist is deleted. 457 */ 458 public function test_delete_data_for_users() { 459 global $DB; 460 461 $this->resetAfterTest(true); 462 463 $component = 'core_notes'; 464 // Test setup. 465 $this->setAdminUser(); 466 set_config('enablenotes', true); 467 // Create a teacher. 468 $teacher1 = $this->getDataGenerator()->create_user(); 469 $this->setUser($teacher1); 470 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 471 // Create a student. 472 $student = $this->getDataGenerator()->create_user(); 473 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 474 475 // Create Courses, then enrol a teacher and a student. 476 $nocourses = 3; 477 for ($c = 1; $c <= $nocourses; $c++) { 478 ${'course' . $c} = $this->getDataGenerator()->create_course(); 479 ${'coursecontext' . $c} = \context_course::instance(${'course' . $c}->id); 480 481 role_assign($teacherrole->id, $teacher1->id, ${'coursecontext' . $c}->id); 482 role_assign($studentrole->id, $student->id, ${'coursecontext' . $c}->id); 483 } 484 485 // Create private notes for student in the course1 and course2 written by the teacher. 486 $this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course1->id, 487 "Test private user note about the student in Course 1 by the teacher"); 488 $this->help_create_user_note($student->id, NOTES_STATE_DRAFT, $course2->id, 489 "Test private user note about the student in Course 2 by the teacher"); 490 // Create public notes for student in the course3 written by the teacher. 491 $this->help_create_user_note($student->id, NOTES_STATE_PUBLIC, $course3->id, 492 "Test public user note about the student in Course 3 by the teacher"); 493 494 // The list of users in coursecontext1 should return one user (teacher1). 495 $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); 496 provider::get_users_in_context($userlist1); 497 $this->assertCount(1, $userlist1); 498 $this->assertTrue(in_array($teacher1->id, $userlist1->get_userids())); 499 // The list of users in coursecontext2 should return one user (teacher1). 500 $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); 501 provider::get_users_in_context($userlist2); 502 $this->assertCount(1, $userlist2); 503 $this->assertTrue(in_array($teacher1->id, $userlist2->get_userids())); 504 // The list of users in coursecontext3 should return two users (teacher1 and student). 505 $userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component); 506 provider::get_users_in_context($userlist3); 507 $this->assertCount(2, $userlist3); 508 $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); 509 $this->assertTrue(in_array($student->id, $userlist3->get_userids())); 510 511 $approvedlist = new approved_userlist($coursecontext3, $component, [$student->id]); 512 // Delete using delete_data_for_user. 513 provider::delete_data_for_users($approvedlist); 514 // Re-fetch users in the coursecontext3. 515 $userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component); 516 // The user data in coursecontext3 should not be removed. 517 provider::get_users_in_context($userlist3); 518 $this->assertCount(2, $userlist3); 519 $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); 520 $this->assertTrue(in_array($student->id, $userlist3->get_userids())); 521 522 $approvedlist = new approved_userlist($coursecontext3, $component, [$teacher1->id]); 523 // Delete using delete_data_for_user. 524 provider::delete_data_for_users($approvedlist); 525 // Re-fetch users in the coursecontext3. 526 $userlist3 = new \core_privacy\local\request\userlist($coursecontext3, $component); 527 // The user data in coursecontext3 should be removed. 528 provider::get_users_in_context($userlist3); 529 $this->assertCount(0, $userlist3); 530 531 // Re-fetch users in the coursecontext1. 532 $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); 533 provider::get_users_in_context($userlist1); 534 $this->assertCount(1, $userlist1); 535 536 $approvedlist = new approved_userlist($coursecontext1, $component, [$student->id]); 537 // Delete using delete_data_for_user. 538 provider::delete_data_for_users($approvedlist); 539 // Re-fetch users in the coursecontext1. 540 $userlist3 = new \core_privacy\local\request\userlist($coursecontext1, $component); 541 // The user data in coursecontext1 should not be removed. 542 provider::get_users_in_context($userlist3); 543 $this->assertCount(1, $userlist3); 544 $this->assertTrue(in_array($teacher1->id, $userlist3->get_userids())); 545 546 $approvedlist = new approved_userlist($coursecontext1, $component, [$teacher1->id]); 547 // Delete using delete_data_for_user. 548 provider::delete_data_for_users($approvedlist); 549 // Re-fetch users in the coursecontext1. 550 $userlist3 = new \core_privacy\local\request\userlist($coursecontext1, $component); 551 // The user data in coursecontext1 should be removed. 552 provider::get_users_in_context($userlist3); 553 $this->assertCount(0, $userlist3); 554 555 // Re-fetch users in the coursecontext2. 556 $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); 557 provider::get_users_in_context($userlist2); 558 $this->assertCount(1, $userlist2); 559 560 // The list of users should not return any users for contexts different than course context. 561 $systemcontext = \context_system::instance(); 562 $userlist4 = new \core_privacy\local\request\userlist($systemcontext, $component); 563 provider::get_users_in_context($userlist4); 564 $this->assertCount(0, $userlist4); 565 } 566 567 /** 568 * Helper function to create user notes for testing. 569 * 570 * @param int $userid The ID of the User associated with the note. 571 * @param string $state The publish status 572 * @param int $courseid The ID of the Course associated with the note. 573 * @param string $content The note content. 574 */ 575 protected function help_create_user_note($userid, $state, $courseid, $content) { 576 $note = (object) [ 577 'userid' => $userid, 578 'publishstate' => $state, 579 'courseid' => $courseid, 580 'content' => $content, 581 ]; 582 note_save($note); 583 } 584 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body