Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
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 lib.php 19 * 20 * @package mod_data 21 * @category phpunit 22 * @copyright 2013 Adrian Greeve 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 namespace mod_data; 26 27 use stdClass; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 global $CFG; 32 require_once($CFG->dirroot . '/mod/data/lib.php'); 33 34 /** 35 * Unit tests for lib.php 36 * 37 * @package mod_data 38 * @copyright 2013 Adrian Greeve 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 */ 41 class lib_test extends \advanced_testcase { 42 43 /** 44 * @var moodle_database 45 */ 46 protected $DB = null; 47 48 /** 49 * Tear Down to reset DB. 50 */ 51 public function tearDown(): void { 52 global $DB; 53 54 if (isset($this->DB)) { 55 $DB = $this->DB; 56 $this->DB = null; 57 } 58 } 59 60 /** 61 * Confirms that completionentries is working 62 * Sets it to 1, confirms that 63 * it is not complete. Inserts a record and 64 * confirms that it is complete. 65 */ 66 public function test_data_completion() { 67 global $DB, $CFG; 68 $this->resetAfterTest(); 69 $this->setAdminUser(); 70 $CFG->enablecompletion = 1; 71 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 72 $record = new \stdClass(); 73 $record->course = $course->id; 74 $record->name = "Mod data completion test"; 75 $record->intro = "Some intro of some sort"; 76 $record->completionentries = "1"; 77 /* completion=2 means Show activity commplete when condition is met and completionentries means 1 record is 78 * required for the activity to be considered complete 79 */ 80 $module = $this->getDataGenerator()->create_module('data', $record, array('completion' => 2, 'completionentries' => 1)); 81 82 $cm = get_coursemodule_from_instance('data', $module->id, $course->id); 83 $completion = new \completion_info($course); 84 $completiondata = $completion->get_data($cm, true, 0); 85 /* Confirm it is not complete as there are no entries */ 86 $this->assertNotEquals(1, $completiondata->completionstate); 87 88 $field = data_get_field_new('text', $module); 89 $fielddetail = new \stdClass(); 90 $fielddetail->d = $module->id; 91 $fielddetail->mode = 'add'; 92 $fielddetail->type = 'text'; 93 $fielddetail->sesskey = sesskey(); 94 $fielddetail->name = 'Name'; 95 $fielddetail->description = 'Some name'; 96 97 $field->define_field($fielddetail); 98 $field->insert_field(); 99 $recordid = data_add_record($module); 100 101 $datacontent = array(); 102 $datacontent['fieldid'] = $field->field->id; 103 $datacontent['recordid'] = $recordid; 104 $datacontent['content'] = 'Asterix'; 105 $contentid = $DB->insert_record('data_content', $datacontent); 106 107 $cm = get_coursemodule_from_instance('data', $module->id, $course->id); 108 $completion = new \completion_info($course); 109 $completiondata = $completion->get_data($cm); 110 /* Confirm it is complete because it has 1 entry */ 111 $this->assertEquals(1, $completiondata->completionstate); 112 } 113 114 public function test_data_delete_record() { 115 global $DB; 116 117 $this->resetAfterTest(); 118 119 // Create a record for deleting. 120 $this->setAdminUser(); 121 $course = $this->getDataGenerator()->create_course(); 122 $record = new \stdClass(); 123 $record->course = $course->id; 124 $record->name = "Mod data delete test"; 125 $record->intro = "Some intro of some sort"; 126 127 $module = $this->getDataGenerator()->create_module('data', $record); 128 129 $field = data_get_field_new('text', $module); 130 131 $fielddetail = new \stdClass(); 132 $fielddetail->d = $module->id; 133 $fielddetail->mode = 'add'; 134 $fielddetail->type = 'text'; 135 $fielddetail->sesskey = sesskey(); 136 $fielddetail->name = 'Name'; 137 $fielddetail->description = 'Some name'; 138 139 $field->define_field($fielddetail); 140 $field->insert_field(); 141 $recordid = data_add_record($module); 142 143 $datacontent = array(); 144 $datacontent['fieldid'] = $field->field->id; 145 $datacontent['recordid'] = $recordid; 146 $datacontent['content'] = 'Asterix'; 147 148 $contentid = $DB->insert_record('data_content', $datacontent); 149 $cm = get_coursemodule_from_instance('data', $module->id, $course->id); 150 151 // Check to make sure that we have a database record. 152 $data = $DB->get_records('data', array('id' => $module->id)); 153 $this->assertEquals(1, count($data)); 154 155 $datacontent = $DB->get_records('data_content', array('id' => $contentid)); 156 $this->assertEquals(1, count($datacontent)); 157 158 $datafields = $DB->get_records('data_fields', array('id' => $field->field->id)); 159 $this->assertEquals(1, count($datafields)); 160 161 $datarecords = $DB->get_records('data_records', array('id' => $recordid)); 162 $this->assertEquals(1, count($datarecords)); 163 164 // Test to see if a failed delete returns false. 165 $result = data_delete_record(8798, $module, $course->id, $cm->id); 166 $this->assertFalse($result); 167 168 // Delete the record. 169 $result = data_delete_record($recordid, $module, $course->id, $cm->id); 170 171 // Check that all of the record is gone. 172 $datacontent = $DB->get_records('data_content', array('id' => $contentid)); 173 $this->assertEquals(0, count($datacontent)); 174 175 $datarecords = $DB->get_records('data_records', array('id' => $recordid)); 176 $this->assertEquals(0, count($datarecords)); 177 178 // Make sure the function returns true on a successful deletion. 179 $this->assertTrue($result); 180 } 181 182 /** 183 * Test comment_created event. 184 */ 185 public function test_data_comment_created_event() { 186 global $CFG, $DB; 187 require_once($CFG->dirroot . '/comment/lib.php'); 188 189 $this->resetAfterTest(); 190 191 // Create a record for deleting. 192 $this->setAdminUser(); 193 $course = $this->getDataGenerator()->create_course(); 194 $record = new \stdClass(); 195 $record->course = $course->id; 196 $record->name = "Mod data delete test"; 197 $record->intro = "Some intro of some sort"; 198 $record->comments = 1; 199 200 $module = $this->getDataGenerator()->create_module('data', $record); 201 $field = data_get_field_new('text', $module); 202 203 $fielddetail = new \stdClass(); 204 $fielddetail->name = 'Name'; 205 $fielddetail->description = 'Some name'; 206 207 $field->define_field($fielddetail); 208 $field->insert_field(); 209 $recordid = data_add_record($module); 210 211 $datacontent = array(); 212 $datacontent['fieldid'] = $field->field->id; 213 $datacontent['recordid'] = $recordid; 214 $datacontent['content'] = 'Asterix'; 215 216 $contentid = $DB->insert_record('data_content', $datacontent); 217 $cm = get_coursemodule_from_instance('data', $module->id, $course->id); 218 219 $context = \context_module::instance($module->cmid); 220 $cmt = new \stdClass(); 221 $cmt->context = $context; 222 $cmt->course = $course; 223 $cmt->cm = $cm; 224 $cmt->area = 'database_entry'; 225 $cmt->itemid = $recordid; 226 $cmt->showcount = true; 227 $cmt->component = 'mod_data'; 228 $comment = new \comment($cmt); 229 230 // Triggering and capturing the event. 231 $sink = $this->redirectEvents(); 232 $comment->add('New comment'); 233 $events = $sink->get_events(); 234 $this->assertCount(1, $events); 235 $event = reset($events); 236 237 // Checking that the event contains the expected values. 238 $this->assertInstanceOf('\mod_data\event\comment_created', $event); 239 $this->assertEquals($context, $event->get_context()); 240 $url = new \moodle_url('/mod/data/view.php', array('id' => $cm->id)); 241 $this->assertEquals($url, $event->get_url()); 242 $this->assertEventContextNotUsed($event); 243 } 244 245 /** 246 * Test comment_deleted event. 247 */ 248 public function test_data_comment_deleted_event() { 249 global $CFG, $DB; 250 require_once($CFG->dirroot . '/comment/lib.php'); 251 252 $this->resetAfterTest(); 253 254 // Create a record for deleting. 255 $this->setAdminUser(); 256 $course = $this->getDataGenerator()->create_course(); 257 $record = new \stdClass(); 258 $record->course = $course->id; 259 $record->name = "Mod data delete test"; 260 $record->intro = "Some intro of some sort"; 261 $record->comments = 1; 262 263 $module = $this->getDataGenerator()->create_module('data', $record); 264 $field = data_get_field_new('text', $module); 265 266 $fielddetail = new \stdClass(); 267 $fielddetail->name = 'Name'; 268 $fielddetail->description = 'Some name'; 269 270 $field->define_field($fielddetail); 271 $field->insert_field(); 272 $recordid = data_add_record($module); 273 274 $datacontent = array(); 275 $datacontent['fieldid'] = $field->field->id; 276 $datacontent['recordid'] = $recordid; 277 $datacontent['content'] = 'Asterix'; 278 279 $contentid = $DB->insert_record('data_content', $datacontent); 280 $cm = get_coursemodule_from_instance('data', $module->id, $course->id); 281 282 $context = \context_module::instance($module->cmid); 283 $cmt = new \stdClass(); 284 $cmt->context = $context; 285 $cmt->course = $course; 286 $cmt->cm = $cm; 287 $cmt->area = 'database_entry'; 288 $cmt->itemid = $recordid; 289 $cmt->showcount = true; 290 $cmt->component = 'mod_data'; 291 $comment = new \comment($cmt); 292 $newcomment = $comment->add('New comment 1'); 293 294 // Triggering and capturing the event. 295 $sink = $this->redirectEvents(); 296 $comment->delete($newcomment->id); 297 $events = $sink->get_events(); 298 $this->assertCount(1, $events); 299 $event = reset($events); 300 301 // Checking that the event contains the expected values. 302 $this->assertInstanceOf('\mod_data\event\comment_deleted', $event); 303 $this->assertEquals($context, $event->get_context()); 304 $url = new \moodle_url('/mod/data/view.php', array('id' => $module->cmid)); 305 $this->assertEquals($url, $event->get_url()); 306 $this->assertEventContextNotUsed($event); 307 } 308 309 /** 310 * Checks that data_user_can_manage_entry will return true if the user 311 * has the mod/data:manageentries capability. 312 */ 313 public function test_data_user_can_manage_entry_return_true_with_capability() { 314 315 $this->resetAfterTest(); 316 $testdata = $this->create_user_test_data(); 317 318 $user = $testdata['user']; 319 $course = $testdata['course']; 320 $roleid = $testdata['roleid']; 321 $context = $testdata['context']; 322 $record = $testdata['record']; 323 $data = new \stdClass(); 324 325 $this->setUser($user); 326 327 assign_capability('mod/data:manageentries', CAP_ALLOW, $roleid, $context); 328 329 $this->assertTrue(data_user_can_manage_entry($record, $data, $context), 330 'data_user_can_manage_entry() returns true if the user has mod/data:manageentries capability'); 331 } 332 333 /** 334 * Checks that data_user_can_manage_entry will return false if the data 335 * is set to readonly. 336 */ 337 public function test_data_user_can_manage_entry_return_false_readonly() { 338 339 $this->resetAfterTest(); 340 $testdata = $this->create_user_test_data(); 341 342 $user = $testdata['user']; 343 $course = $testdata['course']; 344 $roleid = $testdata['roleid']; 345 $context = $testdata['context']; 346 $record = $testdata['record']; 347 348 $this->setUser($user); 349 350 // Need to make sure they don't have this capability in order to fall back to 351 // the other checks. 352 assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); 353 354 // Causes readonly mode to be enabled. 355 $data = new \stdClass(); 356 $now = time(); 357 // Add a small margin around the periods to prevent errors with slow tests. 358 $data->timeviewfrom = $now - 1; 359 $data->timeviewto = $now + 5; 360 361 $this->assertFalse(data_user_can_manage_entry($record, $data, $context), 362 'data_user_can_manage_entry() returns false if the data is read only'); 363 } 364 365 /** 366 * Checks that data_user_can_manage_entry will return false if the record 367 * can't be found in the database. 368 */ 369 public function test_data_user_can_manage_entry_return_false_no_record() { 370 371 $this->resetAfterTest(); 372 $testdata = $this->create_user_test_data(); 373 374 $user = $testdata['user']; 375 $course = $testdata['course']; 376 $roleid = $testdata['roleid']; 377 $context = $testdata['context']; 378 $record = $testdata['record']; 379 $data = new \stdClass(); 380 // Causes readonly mode to be disabled. 381 $now = time(); 382 $data->timeviewfrom = $now + 100; 383 $data->timeviewto = $now - 100; 384 385 $this->setUser($user); 386 387 // Need to make sure they don't have this capability in order to fall back to 388 // the other checks. 389 assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); 390 391 // Pass record id instead of object to force DB lookup. 392 $this->assertFalse(data_user_can_manage_entry(1, $data, $context), 393 'data_user_can_manage_entry() returns false if the record cannot be found'); 394 } 395 396 /** 397 * Checks that data_user_can_manage_entry will return false if the record 398 * isn't owned by the user. 399 */ 400 public function test_data_user_can_manage_entry_return_false_not_owned_record() { 401 402 $this->resetAfterTest(); 403 $testdata = $this->create_user_test_data(); 404 405 $user = $testdata['user']; 406 $course = $testdata['course']; 407 $roleid = $testdata['roleid']; 408 $context = $testdata['context']; 409 $record = $testdata['record']; 410 $data = new \stdClass(); 411 // Causes readonly mode to be disabled. 412 $now = time(); 413 $data->timeviewfrom = $now + 100; 414 $data->timeviewto = $now - 100; 415 // Make sure the record isn't owned by this user. 416 $record->userid = $user->id + 1; 417 418 $this->setUser($user); 419 420 // Need to make sure they don't have this capability in order to fall back to 421 // the other checks. 422 assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); 423 424 $this->assertFalse(data_user_can_manage_entry($record, $data, $context), 425 'data_user_can_manage_entry() returns false if the record isnt owned by the user'); 426 } 427 428 /** 429 * Checks that data_user_can_manage_entry will return true if the data 430 * doesn't require approval. 431 */ 432 public function test_data_user_can_manage_entry_return_true_data_no_approval() { 433 434 $this->resetAfterTest(); 435 $testdata = $this->create_user_test_data(); 436 437 $user = $testdata['user']; 438 $course = $testdata['course']; 439 $roleid = $testdata['roleid']; 440 $context = $testdata['context']; 441 $record = $testdata['record']; 442 $data = new \stdClass(); 443 // Causes readonly mode to be disabled. 444 $now = time(); 445 $data->timeviewfrom = $now + 100; 446 $data->timeviewto = $now - 100; 447 // The record doesn't need approval. 448 $data->approval = false; 449 // Make sure the record is owned by this user. 450 $record->userid = $user->id; 451 452 $this->setUser($user); 453 454 // Need to make sure they don't have this capability in order to fall back to 455 // the other checks. 456 assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); 457 458 $this->assertTrue(data_user_can_manage_entry($record, $data, $context), 459 'data_user_can_manage_entry() returns true if the record doesnt require approval'); 460 } 461 462 /** 463 * Checks that data_user_can_manage_entry will return true if the record 464 * isn't yet approved. 465 */ 466 public function test_data_user_can_manage_entry_return_true_record_unapproved() { 467 468 $this->resetAfterTest(); 469 $testdata = $this->create_user_test_data(); 470 471 $user = $testdata['user']; 472 $course = $testdata['course']; 473 $roleid = $testdata['roleid']; 474 $context = $testdata['context']; 475 $record = $testdata['record']; 476 $data = new \stdClass(); 477 // Causes readonly mode to be disabled. 478 $now = time(); 479 $data->timeviewfrom = $now + 100; 480 $data->timeviewto = $now - 100; 481 // The record needs approval. 482 $data->approval = true; 483 // Make sure the record is owned by this user. 484 $record->userid = $user->id; 485 // The record hasn't yet been approved. 486 $record->approved = false; 487 488 $this->setUser($user); 489 490 // Need to make sure they don't have this capability in order to fall back to 491 // the other checks. 492 assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); 493 494 $this->assertTrue(data_user_can_manage_entry($record, $data, $context), 495 'data_user_can_manage_entry() returns true if the record is not yet approved'); 496 } 497 498 /** 499 * Checks that data_user_can_manage_entry will return the 'manageapproved' 500 * value if the record has already been approved. 501 */ 502 public function test_data_user_can_manage_entry_return_manageapproved() { 503 504 $this->resetAfterTest(); 505 $testdata = $this->create_user_test_data(); 506 507 $user = $testdata['user']; 508 $course = $testdata['course']; 509 $roleid = $testdata['roleid']; 510 $context = $testdata['context']; 511 $record = $testdata['record']; 512 $data = new \stdClass(); 513 // Causes readonly mode to be disabled. 514 $now = time(); 515 $data->timeviewfrom = $now + 100; 516 $data->timeviewto = $now - 100; 517 // The record needs approval. 518 $data->approval = true; 519 // Can the user managed approved records? 520 $data->manageapproved = false; 521 // Make sure the record is owned by this user. 522 $record->userid = $user->id; 523 // The record has been approved. 524 $record->approved = true; 525 526 $this->setUser($user); 527 528 // Need to make sure they don't have this capability in order to fall back to 529 // the other checks. 530 assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); 531 532 $canmanageentry = data_user_can_manage_entry($record, $data, $context); 533 534 // Make sure the result of the check is what ever the manageapproved setting 535 // is set to. 536 $this->assertEquals($data->manageapproved, $canmanageentry, 537 'data_user_can_manage_entry() returns the manageapproved setting on approved records'); 538 } 539 540 /** 541 * Helper method to create a set of test data for data_user_can_manage tests 542 * 543 * @return array contains user, course, roleid, module, context and record 544 */ 545 private function create_user_test_data() { 546 $user = $this->getDataGenerator()->create_user(); 547 $course = $this->getDataGenerator()->create_course(); 548 $roleid = $this->getDataGenerator()->create_role(); 549 $record = new \stdClass(); 550 $record->name = "test name"; 551 $record->intro = "test intro"; 552 $record->comments = 1; 553 $record->course = $course->id; 554 $record->userid = $user->id; 555 556 $module = $this->getDataGenerator()->create_module('data', $record); 557 $cm = get_coursemodule_from_instance('data', $module->id, $course->id); 558 $context = \context_module::instance($module->cmid); 559 560 $this->getDataGenerator()->role_assign($roleid, $user->id, $context->id); 561 562 return array( 563 'user' => $user, 564 'course' => $course, 565 'roleid' => $roleid, 566 'module' => $module, 567 'context' => $context, 568 'record' => $record 569 ); 570 } 571 572 /** 573 * Tests for mod_data_rating_can_see_item_ratings(). 574 * 575 * @throws coding_exception 576 * @throws rating_exception 577 */ 578 public function test_mod_data_rating_can_see_item_ratings() { 579 global $DB; 580 581 $this->resetAfterTest(); 582 583 // Setup test data. 584 $course = new \stdClass(); 585 $course->groupmode = SEPARATEGROUPS; 586 $course->groupmodeforce = true; 587 $course = $this->getDataGenerator()->create_course($course); 588 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id)); 589 $cm = get_coursemodule_from_instance('data', $data->id); 590 $context = \context_module::instance($cm->id); 591 592 // Create users. 593 $user1 = $this->getDataGenerator()->create_user(); 594 $user2 = $this->getDataGenerator()->create_user(); 595 $user3 = $this->getDataGenerator()->create_user(); 596 $user4 = $this->getDataGenerator()->create_user(); 597 598 // Groups and stuff. 599 $role = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST); 600 $this->getDataGenerator()->enrol_user($user1->id, $course->id, $role->id); 601 $this->getDataGenerator()->enrol_user($user2->id, $course->id, $role->id); 602 $this->getDataGenerator()->enrol_user($user3->id, $course->id, $role->id); 603 $this->getDataGenerator()->enrol_user($user4->id, $course->id, $role->id); 604 605 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 606 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 607 groups_add_member($group1, $user1); 608 groups_add_member($group1, $user2); 609 groups_add_member($group2, $user3); 610 groups_add_member($group2, $user4); 611 612 // Add data. 613 $field = data_get_field_new('text', $data); 614 615 $fielddetail = new \stdClass(); 616 $fielddetail->name = 'Name'; 617 $fielddetail->description = 'Some name'; 618 619 $field->define_field($fielddetail); 620 $field->insert_field(); 621 622 // Add a record with a group id of zero (all participants). 623 $recordid1 = data_add_record($data, 0); 624 625 $datacontent = array(); 626 $datacontent['fieldid'] = $field->field->id; 627 $datacontent['recordid'] = $recordid1; 628 $datacontent['content'] = 'Obelix'; 629 $DB->insert_record('data_content', $datacontent); 630 631 $recordid = data_add_record($data, $group1->id); 632 633 $datacontent = array(); 634 $datacontent['fieldid'] = $field->field->id; 635 $datacontent['recordid'] = $recordid; 636 $datacontent['content'] = 'Asterix'; 637 $DB->insert_record('data_content', $datacontent); 638 639 // Now try to access it as various users. 640 unassign_capability('moodle/site:accessallgroups', $role->id); 641 // Eveyone should have access to the record with the group id of zero. 642 $params1 = array('contextid' => 2, 643 'component' => 'mod_data', 644 'ratingarea' => 'entry', 645 'itemid' => $recordid1, 646 'scaleid' => 2); 647 648 $params = array('contextid' => 2, 649 'component' => 'mod_data', 650 'ratingarea' => 'entry', 651 'itemid' => $recordid, 652 'scaleid' => 2); 653 654 $this->setUser($user1); 655 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 656 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 657 $this->setUser($user2); 658 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 659 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 660 $this->setUser($user3); 661 $this->assertFalse(mod_data_rating_can_see_item_ratings($params)); 662 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 663 $this->setUser($user4); 664 $this->assertFalse(mod_data_rating_can_see_item_ratings($params)); 665 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 666 667 // Now try with accessallgroups cap and make sure everything is visible. 668 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $role->id, $context->id); 669 $this->setUser($user1); 670 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 671 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 672 $this->setUser($user2); 673 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 674 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 675 $this->setUser($user3); 676 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 677 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 678 $this->setUser($user4); 679 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 680 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 681 682 // Change group mode and verify visibility. 683 $course->groupmode = VISIBLEGROUPS; 684 $DB->update_record('course', $course); 685 unassign_capability('moodle/site:accessallgroups', $role->id); 686 $this->setUser($user1); 687 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 688 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 689 $this->setUser($user2); 690 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 691 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 692 $this->setUser($user3); 693 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 694 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 695 $this->setUser($user4); 696 $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); 697 $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); 698 699 } 700 701 /** 702 * Tests for mod_data_refresh_events. 703 */ 704 public function test_data_refresh_events() { 705 global $DB; 706 $this->resetAfterTest(); 707 $this->setAdminUser(); 708 709 $timeopen = time(); 710 $timeclose = time() + 86400; 711 712 $course = $this->getDataGenerator()->create_course(); 713 $generator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 714 $params['course'] = $course->id; 715 $params['timeavailablefrom'] = $timeopen; 716 $params['timeavailableto'] = $timeclose; 717 $data = $generator->create_instance($params); 718 719 // Normal case, with existing course. 720 $this->assertTrue(data_refresh_events($course->id)); 721 $eventparams = array('modulename' => 'data', 'instance' => $data->id, 'eventtype' => 'open'); 722 $openevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST); 723 $this->assertEquals($openevent->timestart, $timeopen); 724 725 $eventparams = array('modulename' => 'data', 'instance' => $data->id, 'eventtype' => 'close'); 726 $closeevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST); 727 $this->assertEquals($closeevent->timestart, $timeclose); 728 // In case the course ID is passed as a numeric string. 729 $this->assertTrue(data_refresh_events('' . $course->id)); 730 // Course ID not provided. 731 $this->assertTrue(data_refresh_events()); 732 $eventparams = array('modulename' => 'data'); 733 $events = $DB->get_records('event', $eventparams); 734 foreach ($events as $event) { 735 if ($event->modulename === 'data' && $event->instance === $data->id && $event->eventtype === 'open') { 736 $this->assertEquals($event->timestart, $timeopen); 737 } 738 if ($event->modulename === 'data' && $event->instance === $data->id && $event->eventtype === 'close') { 739 $this->assertEquals($event->timestart, $timeclose); 740 } 741 } 742 } 743 744 /** 745 * Data provider for tests of data_get_config. 746 * 747 * @return array 748 */ 749 public function data_get_config_provider() { 750 $initialdata = (object) [ 751 'template_foo' => true, 752 'template_bar' => false, 753 'template_baz' => null, 754 ]; 755 756 $database = (object) [ 757 'config' => json_encode($initialdata), 758 ]; 759 760 return [ 761 'Return full dataset (no key/default)' => [ 762 [$database], 763 $initialdata, 764 ], 765 'Return full dataset (no default)' => [ 766 [$database, null], 767 $initialdata, 768 ], 769 'Return full dataset' => [ 770 [$database, null, null], 771 $initialdata, 772 ], 773 'Return requested key only, value true, no default' => [ 774 [$database, 'template_foo'], 775 true, 776 ], 777 'Return requested key only, value false, no default' => [ 778 [$database, 'template_bar'], 779 false, 780 ], 781 'Return requested key only, value null, no default' => [ 782 [$database, 'template_baz'], 783 null, 784 ], 785 'Return unknown key, value null, no default' => [ 786 [$database, 'template_bum'], 787 null, 788 ], 789 'Return requested key only, value true, default null' => [ 790 [$database, 'template_foo', null], 791 true, 792 ], 793 'Return requested key only, value false, default null' => [ 794 [$database, 'template_bar', null], 795 false, 796 ], 797 'Return requested key only, value null, default null' => [ 798 [$database, 'template_baz', null], 799 null, 800 ], 801 'Return unknown key, value null, default null' => [ 802 [$database, 'template_bum', null], 803 null, 804 ], 805 'Return requested key only, value true, default 42' => [ 806 [$database, 'template_foo', 42], 807 true, 808 ], 809 'Return requested key only, value false, default 42' => [ 810 [$database, 'template_bar', 42], 811 false, 812 ], 813 'Return requested key only, value null, default 42' => [ 814 [$database, 'template_baz', 42], 815 null, 816 ], 817 'Return unknown key, value null, default 42' => [ 818 [$database, 'template_bum', 42], 819 42, 820 ], 821 ]; 822 } 823 824 /** 825 * Tests for data_get_config. 826 * 827 * @dataProvider data_get_config_provider 828 * @param array $funcargs The args to pass to data_get_config 829 * @param mixed $expectation The expected value 830 */ 831 public function test_data_get_config($funcargs, $expectation) { 832 $this->assertEquals($expectation, call_user_func_array('data_get_config', $funcargs)); 833 } 834 835 /** 836 * Data provider for tests of data_set_config. 837 * 838 * @return array 839 */ 840 public function data_set_config_provider() { 841 $basevalue = (object) ['id' => rand(1, 1000)]; 842 $config = [ 843 'template_foo' => true, 844 'template_bar' => false, 845 ]; 846 847 $withvalues = clone $basevalue; 848 $withvalues->config = json_encode((object) $config); 849 850 return [ 851 'Empty config, New value' => [ 852 $basevalue, 853 'etc', 854 'newvalue', 855 true, 856 json_encode((object) ['etc' => 'newvalue']) 857 ], 858 'Has config, New value' => [ 859 clone $withvalues, 860 'etc', 861 'newvalue', 862 true, 863 json_encode((object) array_merge($config, ['etc' => 'newvalue'])) 864 ], 865 'Has config, Update value, string' => [ 866 clone $withvalues, 867 'template_foo', 868 'newvalue', 869 true, 870 json_encode((object) array_merge($config, ['template_foo' => 'newvalue'])) 871 ], 872 'Has config, Update value, true' => [ 873 clone $withvalues, 874 'template_bar', 875 true, 876 true, 877 json_encode((object) array_merge($config, ['template_bar' => true])) 878 ], 879 'Has config, Update value, false' => [ 880 clone $withvalues, 881 'template_foo', 882 false, 883 true, 884 json_encode((object) array_merge($config, ['template_foo' => false])) 885 ], 886 'Has config, Update value, null' => [ 887 clone $withvalues, 888 'template_foo', 889 null, 890 true, 891 json_encode((object) array_merge($config, ['template_foo' => null])) 892 ], 893 'Has config, No update, value true' => [ 894 clone $withvalues, 895 'template_foo', 896 true, 897 false, 898 $withvalues->config, 899 ], 900 ]; 901 } 902 903 /** 904 * Tests for data_set_config. 905 * 906 * @dataProvider data_set_config_provider 907 * @param object $database The example row for the entry 908 * @param string $key The config key to set 909 * @param mixed $value The value of the key 910 * @param bool $expectupdate Whether we expected an update 911 * @param mixed $newconfigvalue The expected value 912 */ 913 public function test_data_set_config($database, $key, $value, $expectupdate, $newconfigvalue) { 914 global $DB; 915 916 // Mock the database. 917 // Note: Use the actual test class here rather than the abstract because are testing concrete methods. 918 $this->DB = $DB; 919 $DB = $this->getMockBuilder(get_class($DB)) 920 ->onlyMethods(['set_field']) 921 ->getMock(); 922 923 $DB->expects($this->exactly((int) $expectupdate)) 924 ->method('set_field') 925 ->with( 926 'data', 927 'config', 928 $newconfigvalue, 929 ['id' => $database->id] 930 ); 931 932 // Perform the update. 933 data_set_config($database, $key, $value); 934 935 // Ensure that the value was updated by reference in $database. 936 $config = json_decode($database->config); 937 $this->assertEquals($value, $config->$key); 938 } 939 940 public function test_mod_data_get_tagged_records() { 941 $this->resetAfterTest(); 942 $this->setAdminUser(); 943 944 // Setup test data. 945 $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 946 $course1 = $this->getDataGenerator()->create_course(); 947 948 $fieldrecord = new \stdClass(); 949 $fieldrecord->name = 'field-1'; 950 $fieldrecord->type = 'text'; 951 952 $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true)); 953 $field1 = $datagenerator->create_field($fieldrecord, $data1); 954 955 $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); 956 $datagenerator->create_entry($data1, [$field1->field->id => 'value12'], 0, ['Cats', 'mice']); 957 $datagenerator->create_entry($data1, [$field1->field->id => 'value13'], 0, ['Cats']); 958 $datagenerator->create_entry($data1, [$field1->field->id => 'value14'], 0); 959 960 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 961 962 // Admin can see everything. 963 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 964 $this->assertStringContainsString('value11', $res->content); 965 $this->assertStringContainsString('value12', $res->content); 966 $this->assertStringContainsString('value13', $res->content); 967 $this->assertStringNotContainsString('value14', $res->content); 968 } 969 970 public function test_mod_data_get_tagged_records_approval() { 971 global $DB; 972 973 $this->resetAfterTest(); 974 $this->setAdminUser(); 975 976 // Setup test data. 977 $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 978 $course2 = $this->getDataGenerator()->create_course(); 979 $course1 = $this->getDataGenerator()->create_course(); 980 981 $fieldrecord = new \stdClass(); 982 $fieldrecord->name = 'field-1'; 983 $fieldrecord->type = 'text'; 984 985 $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id)); 986 $field1 = $datagenerator->create_field($fieldrecord, $data1); 987 $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id, 'approval' => true)); 988 $field2 = $datagenerator->create_field($fieldrecord, $data2); 989 990 $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); 991 $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats'], ['approved' => false]); 992 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 993 994 // Admin can see everything. 995 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 996 $this->assertStringContainsString('value11', $res->content); 997 $this->assertStringContainsString('value21', $res->content); 998 $this->assertEmpty($res->prevpageurl); 999 $this->assertEmpty($res->nextpageurl); 1000 1001 // Create and enrol a user. 1002 $student = self::getDataGenerator()->create_user(); 1003 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1004 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 1005 $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); 1006 $this->setUser($student); 1007 1008 // User can search data records inside a course. 1009 \core_tag_index_builder::reset_caches(); 1010 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1011 1012 $this->assertStringContainsString('value11', $res->content); 1013 $this->assertStringNotContainsString('value21', $res->content); 1014 1015 $recordtoupdate = new \stdClass(); 1016 $recordtoupdate->id = $record21; 1017 $recordtoupdate->approved = true; 1018 $DB->update_record('data_records', $recordtoupdate); 1019 1020 \core_tag_index_builder::reset_caches(); 1021 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1022 1023 $this->assertStringContainsString('value11', $res->content); 1024 $this->assertStringContainsString('value21', $res->content); 1025 } 1026 1027 public function test_mod_data_get_tagged_records_time() { 1028 global $DB; 1029 1030 $this->resetAfterTest(); 1031 $this->setAdminUser(); 1032 1033 // Setup test data. 1034 $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 1035 $course2 = $this->getDataGenerator()->create_course(); 1036 $course1 = $this->getDataGenerator()->create_course(); 1037 1038 $fieldrecord = new \stdClass(); 1039 $fieldrecord->name = 'field-1'; 1040 $fieldrecord->type = 'text'; 1041 1042 $timefrom = time() - YEARSECS; 1043 $timeto = time() - WEEKSECS; 1044 1045 $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true)); 1046 $field1 = $datagenerator->create_field($fieldrecord, $data1); 1047 $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id, 1048 'timeviewfrom' => $timefrom, 1049 'timeviewto' => $timeto)); 1050 $field2 = $datagenerator->create_field($fieldrecord, $data2); 1051 $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); 1052 $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats']); 1053 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 1054 1055 // Admin can see everything. 1056 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1057 $this->assertStringContainsString('value11', $res->content); 1058 $this->assertStringContainsString('value21', $res->content); 1059 $this->assertEmpty($res->prevpageurl); 1060 $this->assertEmpty($res->nextpageurl); 1061 1062 // Create and enrol a user. 1063 $student = self::getDataGenerator()->create_user(); 1064 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1065 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 1066 $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); 1067 $this->setUser($student); 1068 1069 // User can search data records inside a course. 1070 \core_tag_index_builder::reset_caches(); 1071 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1072 1073 $this->assertStringContainsString('value11', $res->content); 1074 $this->assertStringNotContainsString('value21', $res->content); 1075 1076 $data2->timeviewto = time() + YEARSECS; 1077 $DB->update_record('data', $data2); 1078 1079 \core_tag_index_builder::reset_caches(); 1080 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1081 1082 $this->assertStringContainsString('value11', $res->content); 1083 $this->assertStringContainsString('value21', $res->content); 1084 } 1085 1086 public function test_mod_data_get_tagged_records_course_enrolment() { 1087 global $DB; 1088 1089 $this->resetAfterTest(); 1090 $this->setAdminUser(); 1091 1092 // Setup test data. 1093 $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 1094 $course2 = $this->getDataGenerator()->create_course(); 1095 $course1 = $this->getDataGenerator()->create_course(); 1096 1097 $fieldrecord = new \stdClass(); 1098 $fieldrecord->name = 'field-1'; 1099 $fieldrecord->type = 'text'; 1100 1101 $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true)); 1102 $field1 = $datagenerator->create_field($fieldrecord, $data1); 1103 $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id)); 1104 $field2 = $datagenerator->create_field($fieldrecord, $data2); 1105 1106 $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); 1107 $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats']); 1108 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 1109 1110 // Admin can see everything. 1111 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1112 $this->assertStringContainsString('value11', $res->content); 1113 $this->assertStringContainsString('value21', $res->content); 1114 $this->assertEmpty($res->prevpageurl); 1115 $this->assertEmpty($res->nextpageurl); 1116 1117 // Create and enrol a user. 1118 $student = self::getDataGenerator()->create_user(); 1119 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1120 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 1121 $this->setUser($student); 1122 \core_tag_index_builder::reset_caches(); 1123 1124 // User can search data records inside a course. 1125 $coursecontext = \context_course::instance($course1->id); 1126 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1127 1128 $this->assertStringContainsString('value11', $res->content); 1129 $this->assertStringNotContainsString('value21', $res->content); 1130 1131 $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); 1132 1133 \core_tag_index_builder::reset_caches(); 1134 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1135 1136 $this->assertStringContainsString('value11', $res->content); 1137 $this->assertStringContainsString('value21', $res->content); 1138 } 1139 1140 public function test_mod_data_get_tagged_records_course_groups() { 1141 global $DB; 1142 1143 $this->resetAfterTest(); 1144 $this->setAdminUser(); 1145 1146 // Setup test data. 1147 $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 1148 $course2 = $this->getDataGenerator()->create_course(); 1149 $course1 = $this->getDataGenerator()->create_course(); 1150 1151 $groupa = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'name' => 'groupA')); 1152 $groupb = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'name' => 'groupB')); 1153 1154 $fieldrecord = new \stdClass(); 1155 $fieldrecord->name = 'field-1'; 1156 $fieldrecord->type = 'text'; 1157 1158 $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true)); 1159 $field1 = $datagenerator->create_field($fieldrecord, $data1); 1160 $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id)); 1161 $field2 = $datagenerator->create_field($fieldrecord, $data2); 1162 set_coursemodule_groupmode($data2->cmid, SEPARATEGROUPS); 1163 1164 $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 1165 0, ['Cats', 'Dogs']); 1166 $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 1167 $groupa->id, ['Cats']); 1168 $record22 = $datagenerator->create_entry($data2, [$field2->field->id => 'value22'], 1169 $groupb->id, ['Cats']); 1170 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 1171 1172 // Admin can see everything. 1173 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1174 $this->assertStringContainsString('value11', $res->content); 1175 $this->assertStringContainsString('value21', $res->content); 1176 $this->assertStringContainsString('value22', $res->content); 1177 $this->assertEmpty($res->prevpageurl); 1178 $this->assertEmpty($res->nextpageurl); 1179 1180 // Create and enrol a user. 1181 $student = self::getDataGenerator()->create_user(); 1182 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1183 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 1184 $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); 1185 groups_add_member($groupa, $student); 1186 $this->setUser($student); 1187 \core_tag_index_builder::reset_caches(); 1188 1189 // User can search data records inside a course. 1190 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1191 1192 $this->assertStringContainsString('value11', $res->content); 1193 $this->assertStringContainsString('value21', $res->content); 1194 $this->assertStringNotContainsString('value22', $res->content); 1195 1196 groups_add_member($groupb, $student); 1197 \core_tag_index_builder::reset_caches(); 1198 $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); 1199 1200 $this->assertStringContainsString('value11', $res->content); 1201 $this->assertStringContainsString('value21', $res->content); 1202 $this->assertStringContainsString('value22', $res->content); 1203 } 1204 1205 /** 1206 * Test check_updates_since callback. 1207 */ 1208 public function test_check_updates_since() { 1209 global $DB; 1210 $this->resetAfterTest(); 1211 $this->setAdminUser(); 1212 $course = $this->getDataGenerator()->create_course(); 1213 // Create user. 1214 $student = self::getDataGenerator()->create_user(); 1215 // User enrolment. 1216 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1217 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); 1218 $this->setCurrentTimeStart(); 1219 $record = array( 1220 'course' => $course->id, 1221 ); 1222 $data = $this->getDataGenerator()->create_module('data', $record); 1223 $cm = get_coursemodule_from_instance('data', $data->id, $course->id); 1224 $cm = \cm_info::create($cm); 1225 $this->setUser($student); 1226 1227 // Check that upon creation, the updates are only about the new configuration created. 1228 $onehourago = time() - HOURSECS; 1229 $updates = data_check_updates_since($cm, $onehourago); 1230 foreach ($updates as $el => $val) { 1231 if ($el == 'configuration') { 1232 $this->assertTrue($val->updated); 1233 $this->assertTimeCurrent($val->timeupdated); 1234 } else { 1235 $this->assertFalse($val->updated); 1236 } 1237 } 1238 1239 // Add a couple of entries. 1240 $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 1241 $fieldtypes = array('checkbox', 'date'); 1242 1243 $count = 1; 1244 // Creating test Fields with default parameter values. 1245 foreach ($fieldtypes as $fieldtype) { 1246 // Creating variables dynamically. 1247 $fieldname = 'field-' . $count; 1248 $record = new \stdClass(); 1249 $record->name = $fieldname; 1250 $record->type = $fieldtype; 1251 $record->required = 1; 1252 1253 ${$fieldname} = $datagenerator->create_field($record, $data); 1254 $count++; 1255 } 1256 1257 $fields = $DB->get_records('data_fields', array('dataid' => $data->id), 'id'); 1258 1259 $contents = array(); 1260 $contents[] = array('opt1', 'opt2', 'opt3', 'opt4'); 1261 $contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows. 1262 $count = 0; 1263 $fieldcontents = array(); 1264 foreach ($fields as $fieldrecord) { 1265 $fieldcontents[$fieldrecord->id] = $contents[$count++]; 1266 } 1267 1268 $datarecor1did = $datagenerator->create_entry($data, $fieldcontents); 1269 $datarecor2did = $datagenerator->create_entry($data, $fieldcontents); 1270 $records = $DB->get_records('data_records', array('dataid' => $data->id)); 1271 $this->assertCount(2, $records); 1272 // Check we received the entries updated. 1273 $updates = data_check_updates_since($cm, $onehourago); 1274 $this->assertTrue($updates->entries->updated); 1275 $this->assertEqualsCanonicalizing([$datarecor1did, $datarecor2did], $updates->entries->itemids); 1276 } 1277 1278 public function test_data_core_calendar_provide_event_action_in_hidden_section() { 1279 global $CFG; 1280 1281 $this->resetAfterTest(); 1282 1283 $this->setAdminUser(); 1284 1285 // Create a course. 1286 $course = $this->getDataGenerator()->create_course(); 1287 1288 // Create a student. 1289 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 1290 1291 // Create a database activity. 1292 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 1293 'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS)); 1294 1295 // Create a calendar event. 1296 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1297 1298 // Set sections 0 as hidden. 1299 set_section_visible($course->id, 0, 0); 1300 1301 // Now, log out. 1302 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 1303 $this->setUser(); 1304 1305 // Create an action factory. 1306 $factory = new \core_calendar\action_factory(); 1307 1308 // Decorate action event for the student. 1309 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); 1310 1311 // Confirm the event is not shown at all. 1312 $this->assertNull($actionevent); 1313 } 1314 1315 public function test_data_core_calendar_provide_event_action_for_non_user() { 1316 global $CFG; 1317 1318 $this->resetAfterTest(); 1319 1320 $this->setAdminUser(); 1321 1322 // Create a course. 1323 $course = $this->getDataGenerator()->create_course(); 1324 1325 // Create a database activity. 1326 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 1327 'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS)); 1328 1329 // Create a calendar event. 1330 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1331 1332 // Now, log out. 1333 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 1334 $this->setUser(); 1335 1336 // Create an action factory. 1337 $factory = new \core_calendar\action_factory(); 1338 1339 // Decorate action event. 1340 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); 1341 1342 // Confirm the event is not shown at all. 1343 $this->assertNull($actionevent); 1344 } 1345 1346 public function test_data_core_calendar_provide_event_action_open() { 1347 $this->resetAfterTest(); 1348 1349 $this->setAdminUser(); 1350 1351 // Create a course. 1352 $course = $this->getDataGenerator()->create_course(); 1353 1354 // Create a database activity. 1355 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 1356 'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS)); 1357 1358 // Create a calendar event. 1359 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1360 1361 // Create an action factory. 1362 $factory = new \core_calendar\action_factory(); 1363 1364 // Decorate action event. 1365 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); 1366 1367 // Confirm the event was decorated. 1368 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 1369 $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); 1370 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 1371 $this->assertEquals(1, $actionevent->get_item_count()); 1372 $this->assertTrue($actionevent->is_actionable()); 1373 } 1374 1375 public function test_data_core_calendar_provide_event_action_open_for_user() { 1376 global $CFG; 1377 1378 $this->resetAfterTest(); 1379 1380 $this->setAdminUser(); 1381 1382 // Create a course. 1383 $course = $this->getDataGenerator()->create_course(); 1384 1385 // Create a student. 1386 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 1387 1388 // Create a database activity. 1389 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 1390 'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS)); 1391 1392 // Create a calendar event. 1393 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1394 1395 // Now log out. 1396 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 1397 $this->setUser(); 1398 1399 // Create an action factory. 1400 $factory = new \core_calendar\action_factory(); 1401 1402 // Decorate action event for the student. 1403 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); 1404 1405 // Confirm the event was decorated. 1406 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 1407 $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); 1408 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 1409 $this->assertEquals(1, $actionevent->get_item_count()); 1410 $this->assertTrue($actionevent->is_actionable()); 1411 } 1412 1413 public function test_data_core_calendar_provide_event_action_closed() { 1414 $this->resetAfterTest(); 1415 1416 $this->setAdminUser(); 1417 1418 // Create a course. 1419 $course = $this->getDataGenerator()->create_course(); 1420 1421 // Create a database activity. 1422 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 1423 'timeavailableto' => time() - DAYSECS)); 1424 1425 // Create a calendar event. 1426 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1427 1428 // Create an action factory. 1429 $factory = new \core_calendar\action_factory(); 1430 1431 // Decorate action event. 1432 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); 1433 1434 // No event on the dashboard if module is closed. 1435 $this->assertNull($actionevent); 1436 } 1437 1438 public function test_data_core_calendar_provide_event_action_closed_for_user() { 1439 $this->resetAfterTest(); 1440 1441 $this->setAdminUser(); 1442 1443 // Create a course. 1444 $course = $this->getDataGenerator()->create_course(); 1445 1446 // Create a student. 1447 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 1448 1449 // Create a database activity. 1450 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 1451 'timeavailableto' => time() - DAYSECS)); 1452 1453 // Create a calendar event. 1454 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1455 1456 // Now log out. 1457 $this->setUser(); 1458 1459 // Create an action factory. 1460 $factory = new \core_calendar\action_factory(); 1461 1462 // Decorate action event for the student. 1463 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); 1464 1465 // No event on the dashboard if module is closed. 1466 $this->assertNull($actionevent); 1467 } 1468 1469 public function test_data_core_calendar_provide_event_action_open_in_future() { 1470 $this->resetAfterTest(); 1471 1472 $this->setAdminUser(); 1473 1474 // Create a course. 1475 $course = $this->getDataGenerator()->create_course(); 1476 1477 // Create a database activity. 1478 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 1479 'timeavailablefrom' => time() + DAYSECS)); 1480 1481 // Create a calendar event. 1482 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1483 1484 // Create an action factory. 1485 $factory = new \core_calendar\action_factory(); 1486 1487 // Decorate action event. 1488 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); 1489 1490 // Confirm the event was decorated. 1491 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 1492 $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); 1493 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 1494 $this->assertEquals(1, $actionevent->get_item_count()); 1495 $this->assertFalse($actionevent->is_actionable()); 1496 } 1497 1498 public function test_data_core_calendar_provide_event_action_open_in_future_for_user() { 1499 global $CFG; 1500 1501 $this->resetAfterTest(); 1502 1503 $this->setAdminUser(); 1504 1505 // Create a course. 1506 $course = $this->getDataGenerator()->create_course(); 1507 1508 // Create a student. 1509 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 1510 1511 // Create a database activity. 1512 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 1513 'timeavailablefrom' => time() + DAYSECS)); 1514 1515 // Create a calendar event. 1516 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1517 1518 // Now log out. 1519 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 1520 $this->setUser(); 1521 1522 // Create an action factory. 1523 $factory = new \core_calendar\action_factory(); 1524 1525 // Decorate action event for the student. 1526 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); 1527 1528 // Confirm the event was decorated. 1529 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 1530 $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); 1531 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 1532 $this->assertEquals(1, $actionevent->get_item_count()); 1533 $this->assertFalse($actionevent->is_actionable()); 1534 } 1535 1536 public function test_data_core_calendar_provide_event_action_no_time_specified() { 1537 $this->resetAfterTest(); 1538 1539 $this->setAdminUser(); 1540 1541 // Create a course. 1542 $course = $this->getDataGenerator()->create_course(); 1543 1544 // Create a database activity. 1545 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id)); 1546 1547 // Create a calendar event. 1548 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1549 1550 // Create an action factory. 1551 $factory = new \core_calendar\action_factory(); 1552 1553 // Decorate action event. 1554 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); 1555 1556 // Confirm the event was decorated. 1557 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 1558 $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); 1559 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 1560 $this->assertEquals(1, $actionevent->get_item_count()); 1561 $this->assertTrue($actionevent->is_actionable()); 1562 } 1563 1564 public function test_data_core_calendar_provide_event_action_no_time_specified_for_user() { 1565 global $CFG; 1566 1567 $this->resetAfterTest(); 1568 1569 $this->setAdminUser(); 1570 1571 // Create a course. 1572 $course = $this->getDataGenerator()->create_course(); 1573 1574 // Create a student. 1575 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 1576 1577 // Create a database activity. 1578 $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id)); 1579 1580 // Create a calendar event. 1581 $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); 1582 1583 // Now log out. 1584 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 1585 $this->setUser(); 1586 1587 // Create an action factory. 1588 $factory = new \core_calendar\action_factory(); 1589 1590 // Decorate action event for the student. 1591 $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); 1592 1593 // Confirm the event was decorated. 1594 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 1595 $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); 1596 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 1597 $this->assertEquals(1, $actionevent->get_item_count()); 1598 $this->assertTrue($actionevent->is_actionable()); 1599 } 1600 1601 /** 1602 * Creates an action event. 1603 * 1604 * @param int $courseid 1605 * @param int $instanceid The data id. 1606 * @param string $eventtype The event type. eg. DATA_EVENT_TYPE_OPEN. 1607 * @param int|null $timestart The start timestamp for the event 1608 * @return bool|calendar_event 1609 */ 1610 private function create_action_event($courseid, $instanceid, $eventtype, $timestart = null) { 1611 $event = new \stdClass(); 1612 $event->name = 'Calendar event'; 1613 $event->modulename = 'data'; 1614 $event->courseid = $courseid; 1615 $event->instance = $instanceid; 1616 $event->type = CALENDAR_EVENT_TYPE_ACTION; 1617 $event->eventtype = $eventtype; 1618 if ($timestart) { 1619 $event->timestart = $timestart; 1620 } else { 1621 $event->timestart = time(); 1622 } 1623 1624 return \calendar_event::create($event); 1625 } 1626 1627 /** 1628 * Test the callback responsible for returning the completion rule descriptions. 1629 * This function should work given either an instance of the module (cm_info), such as when checking the active rules, 1630 * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type. 1631 */ 1632 public function test_mod_data_completion_get_active_rule_descriptions() { 1633 $this->resetAfterTest(); 1634 $this->setAdminUser(); 1635 1636 // Two activities, both with automatic completion. One has the 'completionentries' rule, one doesn't. 1637 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]); 1638 $data1 = $this->getDataGenerator()->create_module('data', [ 1639 'course' => $course->id, 1640 'completion' => 2, 1641 'completionentries' => 3 1642 ]); 1643 $data2 = $this->getDataGenerator()->create_module('data', [ 1644 'course' => $course->id, 1645 'completion' => 2, 1646 'completionentries' => 0 1647 ]); 1648 $cm1 = \cm_info::create(get_coursemodule_from_instance('data', $data1->id)); 1649 $cm2 = \cm_info::create(get_coursemodule_from_instance('data', $data2->id)); 1650 1651 // Data for the stdClass input type. 1652 // This type of input would occur when checking the default completion rules for an activity type, where we don't have 1653 // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info. 1654 $moddefaults = new \stdClass(); 1655 $moddefaults->customdata = ['customcompletionrules' => ['completionentries' => 3]]; 1656 $moddefaults->completion = 2; 1657 1658 $activeruledescriptions = [get_string('completionentriesdesc', 'data', 3)]; 1659 $this->assertEquals(mod_data_get_completion_active_rule_descriptions($cm1), $activeruledescriptions); 1660 $this->assertEquals(mod_data_get_completion_active_rule_descriptions($cm2), []); 1661 $this->assertEquals(mod_data_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions); 1662 $this->assertEquals(mod_data_get_completion_active_rule_descriptions(new \stdClass()), []); 1663 } 1664 1665 /** 1666 * An unknown event type should not change the data instance. 1667 */ 1668 public function test_mod_data_core_calendar_event_timestart_updated_unknown_event() { 1669 global $CFG, $DB; 1670 require_once($CFG->dirroot . "/calendar/lib.php"); 1671 1672 $this->resetAfterTest(true); 1673 $this->setAdminUser(); 1674 $generator = $this->getDataGenerator(); 1675 $course = $generator->create_course(); 1676 $datagenerator = $generator->get_plugin_generator('mod_data'); 1677 $timeopen = time(); 1678 $timeclose = $timeopen + DAYSECS; 1679 $data = $datagenerator->create_instance(['course' => $course->id]); 1680 $data->timeavailablefrom = $timeopen; 1681 $data->timeavailableto = $timeclose; 1682 $DB->update_record('data', $data); 1683 1684 // Create a valid event. 1685 $event = new \calendar_event([ 1686 'name' => 'Test event', 1687 'description' => '', 1688 'format' => 1, 1689 'courseid' => $course->id, 1690 'groupid' => 0, 1691 'userid' => 2, 1692 'modulename' => 'data', 1693 'instance' => $data->id, 1694 'eventtype' => DATA_EVENT_TYPE_OPEN . "SOMETHING ELSE", 1695 'timestart' => 1, 1696 'timeduration' => 86400, 1697 'visible' => 1 1698 ]); 1699 1700 mod_data_core_calendar_event_timestart_updated($event, $data); 1701 $data = $DB->get_record('data', ['id' => $data->id]); 1702 $this->assertEquals($timeopen, $data->timeavailablefrom); 1703 $this->assertEquals($timeclose, $data->timeavailableto); 1704 } 1705 1706 /** 1707 * A DATA_EVENT_TYPE_OPEN event should update the timeavailablefrom property of the data activity. 1708 */ 1709 public function test_mod_data_core_calendar_event_timestart_updated_open_event() { 1710 global $CFG, $DB; 1711 require_once($CFG->dirroot . "/calendar/lib.php"); 1712 1713 $this->resetAfterTest(true); 1714 $this->setAdminUser(); 1715 $generator = $this->getDataGenerator(); 1716 $course = $generator->create_course(); 1717 $datagenerator = $generator->get_plugin_generator('mod_data'); 1718 $timeopen = time(); 1719 $timeclose = $timeopen + DAYSECS; 1720 $timemodified = 1; 1721 $newtimeopen = $timeopen - DAYSECS; 1722 $data = $datagenerator->create_instance(['course' => $course->id]); 1723 $data->timeavailablefrom = $timeopen; 1724 $data->timeavailableto = $timeclose; 1725 $data->timemodified = $timemodified; 1726 $DB->update_record('data', $data); 1727 1728 // Create a valid event. 1729 $event = new \calendar_event([ 1730 'name' => 'Test event', 1731 'description' => '', 1732 'format' => 1, 1733 'courseid' => $course->id, 1734 'groupid' => 0, 1735 'userid' => 2, 1736 'modulename' => 'data', 1737 'instance' => $data->id, 1738 'eventtype' => DATA_EVENT_TYPE_OPEN, 1739 'timestart' => $newtimeopen, 1740 'timeduration' => 86400, 1741 'visible' => 1 1742 ]); 1743 1744 // Trigger and capture the event when adding a contact. 1745 $sink = $this->redirectEvents(); 1746 mod_data_core_calendar_event_timestart_updated($event, $data); 1747 $triggeredevents = $sink->get_events(); 1748 $moduleupdatedevents = array_filter($triggeredevents, function($e) { 1749 return is_a($e, 'core\event\course_module_updated'); 1750 }); 1751 $data = $DB->get_record('data', ['id' => $data->id]); 1752 1753 // Ensure the timeavailablefrom property matches the event timestart. 1754 $this->assertEquals($newtimeopen, $data->timeavailablefrom); 1755 // Ensure the timeavailableto isn't changed. 1756 $this->assertEquals($timeclose, $data->timeavailableto); 1757 // Ensure the timemodified property has been changed. 1758 $this->assertNotEquals($timemodified, $data->timemodified); 1759 // Confirm that a module updated event is fired when the module is changed. 1760 $this->assertNotEmpty($moduleupdatedevents); 1761 } 1762 1763 /** 1764 * A DATA_EVENT_TYPE_CLOSE event should update the timeavailableto property of the data activity. 1765 */ 1766 public function test_mod_data_core_calendar_event_timestart_updated_close_event() { 1767 global $CFG, $DB; 1768 require_once($CFG->dirroot . "/calendar/lib.php"); 1769 1770 $this->resetAfterTest(true); 1771 $this->setAdminUser(); 1772 $generator = $this->getDataGenerator(); 1773 $course = $generator->create_course(); 1774 $datagenerator = $generator->get_plugin_generator('mod_data'); 1775 $timeopen = time(); 1776 $timeclose = $timeopen + DAYSECS; 1777 $timemodified = 1; 1778 $newtimeclose = $timeclose + DAYSECS; 1779 $data = $datagenerator->create_instance(['course' => $course->id]); 1780 $data->timeavailablefrom = $timeopen; 1781 $data->timeavailableto = $timeclose; 1782 $data->timemodified = $timemodified; 1783 $DB->update_record('data', $data); 1784 1785 // Create a valid event. 1786 $event = new \calendar_event([ 1787 'name' => 'Test event', 1788 'description' => '', 1789 'format' => 1, 1790 'courseid' => $course->id, 1791 'groupid' => 0, 1792 'userid' => 2, 1793 'modulename' => 'data', 1794 'instance' => $data->id, 1795 'eventtype' => DATA_EVENT_TYPE_CLOSE, 1796 'timestart' => $newtimeclose, 1797 'timeduration' => 86400, 1798 'visible' => 1 1799 ]); 1800 1801 // Trigger and capture the event when adding a contact. 1802 $sink = $this->redirectEvents(); 1803 mod_data_core_calendar_event_timestart_updated($event, $data); 1804 $triggeredevents = $sink->get_events(); 1805 $moduleupdatedevents = array_filter($triggeredevents, function($e) { 1806 return is_a($e, 'core\event\course_module_updated'); 1807 }); 1808 $data = $DB->get_record('data', ['id' => $data->id]); 1809 1810 // Ensure the timeavailableto property matches the event timestart. 1811 $this->assertEquals($newtimeclose, $data->timeavailableto); 1812 // Ensure the timeavailablefrom isn't changed. 1813 $this->assertEquals($timeopen, $data->timeavailablefrom); 1814 // Ensure the timemodified property has been changed. 1815 $this->assertNotEquals($timemodified, $data->timemodified); 1816 // Confirm that a module updated event is fired when the module is changed. 1817 $this->assertNotEmpty($moduleupdatedevents); 1818 } 1819 1820 /** 1821 * An unknown event type should not have any limits. 1822 */ 1823 public function test_mod_data_core_calendar_get_valid_event_timestart_range_unknown_event() { 1824 global $CFG; 1825 require_once($CFG->dirroot . "/calendar/lib.php"); 1826 1827 $this->resetAfterTest(true); 1828 $this->setAdminUser(); 1829 $generator = $this->getDataGenerator(); 1830 $course = $generator->create_course(); 1831 $timeopen = time(); 1832 $timeclose = $timeopen + DAYSECS; 1833 $data = new \stdClass(); 1834 $data->timeavailablefrom = $timeopen; 1835 $data->timeavailableto = $timeclose; 1836 1837 // Create a valid event. 1838 $event = new \calendar_event([ 1839 'name' => 'Test event', 1840 'description' => '', 1841 'format' => 1, 1842 'courseid' => $course->id, 1843 'groupid' => 0, 1844 'userid' => 2, 1845 'modulename' => 'data', 1846 'instance' => 1, 1847 'eventtype' => DATA_EVENT_TYPE_OPEN . "SOMETHING ELSE", 1848 'timestart' => 1, 1849 'timeduration' => 86400, 1850 'visible' => 1 1851 ]); 1852 1853 list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); 1854 $this->assertNull($min); 1855 $this->assertNull($max); 1856 } 1857 1858 /** 1859 * The open event should be limited by the data's timeclose property, if it's set. 1860 */ 1861 public function test_mod_data_core_calendar_get_valid_event_timestart_range_open_event() { 1862 global $CFG; 1863 require_once($CFG->dirroot . "/calendar/lib.php"); 1864 1865 $this->resetAfterTest(true); 1866 $this->setAdminUser(); 1867 $generator = $this->getDataGenerator(); 1868 $course = $generator->create_course(); 1869 $timeopen = time(); 1870 $timeclose = $timeopen + DAYSECS; 1871 $data = new \stdClass(); 1872 $data->timeavailablefrom = $timeopen; 1873 $data->timeavailableto = $timeclose; 1874 1875 // Create a valid event. 1876 $event = new \calendar_event([ 1877 'name' => 'Test event', 1878 'description' => '', 1879 'format' => 1, 1880 'courseid' => $course->id, 1881 'groupid' => 0, 1882 'userid' => 2, 1883 'modulename' => 'data', 1884 'instance' => 1, 1885 'eventtype' => DATA_EVENT_TYPE_OPEN, 1886 'timestart' => 1, 1887 'timeduration' => 86400, 1888 'visible' => 1 1889 ]); 1890 1891 // The max limit should be bounded by the timeclose value. 1892 list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); 1893 $this->assertNull($min); 1894 $this->assertEquals($timeclose, $max[0]); 1895 1896 // No timeclose value should result in no upper limit. 1897 $data->timeavailableto = 0; 1898 list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); 1899 $this->assertNull($min); 1900 $this->assertNull($max); 1901 } 1902 1903 /** 1904 * The close event should be limited by the data's timeavailablefrom property, if it's set. 1905 */ 1906 public function test_mod_data_core_calendar_get_valid_event_timestart_range_close_event() { 1907 global $CFG; 1908 1909 require_once($CFG->dirroot . "/calendar/lib.php"); 1910 1911 $this->resetAfterTest(true); 1912 $this->setAdminUser(); 1913 $generator = $this->getDataGenerator(); 1914 $course = $generator->create_course(); 1915 $timeopen = time(); 1916 $timeclose = $timeopen + DAYSECS; 1917 $data = new \stdClass(); 1918 $data->timeavailablefrom = $timeopen; 1919 $data->timeavailableto = $timeclose; 1920 1921 // Create a valid event. 1922 $event = new \calendar_event([ 1923 'name' => 'Test event', 1924 'description' => '', 1925 'format' => 1, 1926 'courseid' => $course->id, 1927 'groupid' => 0, 1928 'userid' => 2, 1929 'modulename' => 'data', 1930 'instance' => 1, 1931 'eventtype' => DATA_EVENT_TYPE_CLOSE, 1932 'timestart' => 1, 1933 'timeduration' => 86400, 1934 'visible' => 1 1935 ]); 1936 1937 // The max limit should be bounded by the timeclose value. 1938 list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); 1939 $this->assertEquals($timeopen, $min[0]); 1940 $this->assertNull($max); 1941 1942 // No timeavailableto value should result in no upper limit. 1943 $data->timeavailablefrom = 0; 1944 list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); 1945 $this->assertNull($min); 1946 $this->assertNull($max); 1947 } 1948 1949 /** 1950 * A user who does not have capabilities to add events to the calendar should be able to create an database. 1951 */ 1952 public function test_creation_with_no_calendar_capabilities() { 1953 $this->resetAfterTest(); 1954 $course = self::getDataGenerator()->create_course(); 1955 $context = \context_course::instance($course->id); 1956 $user = self::getDataGenerator()->create_and_enrol($course, 'editingteacher'); 1957 $roleid = self::getDataGenerator()->create_role(); 1958 self::getDataGenerator()->role_assign($roleid, $user->id, $context->id); 1959 assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true); 1960 $generator = self::getDataGenerator()->get_plugin_generator('mod_data'); 1961 // Create an instance as a user without the calendar capabilities. 1962 $this->setUser($user); 1963 $time = time(); 1964 $params = array( 1965 'course' => $course->id, 1966 'timeavailablefrom' => $time + 200, 1967 'timeavailableto' => $time + 2000, 1968 'timeviewfrom' => $time + 400, 1969 'timeviewto' => $time + 2000, 1970 ); 1971 $generator->create_instance($params); 1972 } 1973 1974 /** 1975 * Test for data_generate_default_template(). This method covers different scenarios for checking when the returned value 1976 * is empty or not, but doesn't check if the content has the expected value when it's not empty. 1977 * 1978 * @covers ::data_generate_default_template 1979 */ 1980 public function test_data_generate_default_template(): void { 1981 $this->resetAfterTest(); 1982 $this->setAdminUser(); 1983 1984 $course = $this->getDataGenerator()->create_course(); 1985 $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]); 1986 1987 // Check the result is empty when $data and/or $template are null. 1988 $nullactivity = null; 1989 $result = data_generate_default_template($nullactivity, 'listtemplate', 0, false, false); 1990 $this->assertEmpty($result); 1991 $result = data_generate_default_template($activity, null, 0, false, false); 1992 $this->assertEmpty($result); 1993 $result = data_generate_default_template($nullactivity, null, 0, false, false); 1994 $this->assertEmpty($result); 1995 1996 // Check the result is empty when any of the templates that are empty are given. 1997 $emptytemplates = [ 1998 'csstemplate', 1999 'jstemplate', 2000 'listtemplateheader', 2001 'listtemplatefooter', 2002 'rsstitletemplate', 2003 ]; 2004 foreach ($emptytemplates as $emptytemplate) { 2005 $result = data_generate_default_template($activity, $emptytemplate, 0, false, false); 2006 $this->assertEmpty($result); 2007 } 2008 2009 $templates = [ 2010 'listtemplate', 2011 'singletemplate', 2012 'asearchtemplate', 2013 ]; 2014 // Check the result is empty when the database has no fields. 2015 foreach ($templates as $template) { 2016 $result = data_generate_default_template($activity, $template, 0, false, false); 2017 $this->assertEmpty($result); 2018 $this->assertEmpty($activity->{$template}); 2019 } 2020 2021 // Add a field to the activity. 2022 $fieldrecord = new stdClass(); 2023 $fieldrecord->name = 'field-1'; 2024 $fieldrecord->type = 'text'; 2025 $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 2026 $datagenerator->create_field($fieldrecord, $activity); 2027 2028 // Check the result is not empty when the database has no entries. 2029 foreach ($templates as $template) { 2030 $result = data_generate_default_template($activity, $template, 0, false, false); 2031 $this->assertNotEmpty($result); 2032 $this->assertEmpty($activity->{$template}); 2033 } 2034 2035 // Check the result is not empty when the database has no entries and the result is saved when $update = true. 2036 foreach ($templates as $template) { 2037 $result = data_generate_default_template($activity, $template, 0, false, true); 2038 $this->assertNotEmpty($result); 2039 $this->assertNotEmpty($activity->{$template}); 2040 } 2041 } 2042 2043 /** 2044 * Test for data_replace_field_in_templates(). 2045 * 2046 * @covers ::data_replace_field_in_templates 2047 */ 2048 public function test_data_replace_field_in_templates(): void { 2049 global $DB; 2050 $this->resetAfterTest(); 2051 $this->setAdminUser(); 2052 2053 $course = $this->getDataGenerator()->create_course(); 2054 $templatecontent = "Field [[myfield]], [[myfield#id]], [[myfield#name]], [[myfield#description]], "; 2055 2056 $params = ['course' => $course]; 2057 foreach (manager::TEMPLATES_LIST as $templatename => $templatefile) { 2058 $params[$templatename] = $templatecontent; 2059 } 2060 $activity = $this->getDataGenerator()->create_module(manager::MODULE, $params); 2061 2062 $generator = $this->getDataGenerator()->get_plugin_generator(manager::PLUGINNAME); 2063 $fieldrecord = (object)['name' => 'myfield', 'type' => 'text', 'description' => 'This is a field']; 2064 $generator->create_field($fieldrecord, $activity); 2065 2066 data_replace_field_in_templates($activity, 'myfield', 'newfieldname'); 2067 $dbactivity = $DB->get_record(manager::MODULE, ['id' => $activity->id]); 2068 2069 $newcontent = "Field [[newfieldname]], [[newfieldname#id]], [[newfieldname#name]], [[newfieldname#description]], "; 2070 // Field compatible templates. 2071 $this->assertEquals($newcontent, $dbactivity->listtemplate); 2072 $this->assertEquals($newcontent, $dbactivity->singletemplate); 2073 $this->assertEquals($newcontent, $dbactivity->asearchtemplate); 2074 $this->assertEquals($newcontent, $dbactivity->addtemplate); 2075 $this->assertEquals($newcontent, $dbactivity->rsstemplate); 2076 // Other templates. 2077 $this->assertEquals($templatecontent, $dbactivity->listtemplateheader); 2078 $this->assertEquals($templatecontent, $dbactivity->listtemplatefooter); 2079 $this->assertEquals($templatecontent, $dbactivity->csstemplate); 2080 $this->assertEquals($templatecontent, $dbactivity->jstemplate); 2081 $this->assertEquals($templatecontent, $dbactivity->rsstitletemplate); 2082 } 2083 2084 /** 2085 * Test for data_append_new_field_to_templates(). 2086 * 2087 * @covers ::data_append_new_field_to_templates 2088 * @dataProvider data_append_new_field_to_templates_provider 2089 * @param bool $hasfield if the field is present in the templates 2090 * @param bool $hasotherfields if the field is not present in the templates 2091 * @param bool $expected the expected return 2092 */ 2093 public function test_data_append_new_field_to_templates(bool $hasfield, bool $hasotherfields, bool $expected) { 2094 global $DB; 2095 $this->resetAfterTest(); 2096 $this->setAdminUser(); 2097 2098 $templatecontent = "Template content"; 2099 if ($hasfield) { 2100 $templatecontent .= "Has [[myfield]]."; 2101 } 2102 if ($hasotherfields) { 2103 $templatecontent .= "And also ##otherfields##."; 2104 } 2105 2106 $course = $this->getDataGenerator()->create_course(); 2107 $params = ['course' => $course]; 2108 foreach (manager::TEMPLATES_LIST as $templatename => $templatefile) { 2109 $params[$templatename] = $templatecontent; 2110 } 2111 $activity = $this->getDataGenerator()->create_module(manager::MODULE, $params); 2112 2113 $result = data_append_new_field_to_templates($activity, 'myfield'); 2114 $this->assertEquals($expected, $result); 2115 2116 // Check fields with auto add fields. 2117 $dbactivity = $DB->get_record(manager::MODULE, ['id' => $activity->id]); 2118 if ($hasfield || $hasotherfields) { 2119 $this->assertEquals($dbactivity->singletemplate, $templatecontent); 2120 $this->assertEquals($dbactivity->addtemplate, $templatecontent); 2121 $this->assertEquals($dbactivity->rsstemplate, $templatecontent); 2122 } else { 2123 $regexp = '|Template content.*\[\[myfield\]\]|'; 2124 // We don't want line breaks for the validations. 2125 $this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->singletemplate)); 2126 $this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->addtemplate)); 2127 $this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->rsstemplate)); 2128 } 2129 // No auto add field templates. 2130 $this->assertEquals($dbactivity->asearchtemplate, $templatecontent); 2131 $this->assertEquals($dbactivity->listtemplate, $templatecontent); 2132 $this->assertEquals($dbactivity->listtemplateheader, $templatecontent); 2133 $this->assertEquals($dbactivity->listtemplatefooter, $templatecontent); 2134 $this->assertEquals($dbactivity->csstemplate, $templatecontent); 2135 $this->assertEquals($dbactivity->jstemplate, $templatecontent); 2136 $this->assertEquals($dbactivity->rsstitletemplate, $templatecontent); 2137 } 2138 2139 /** 2140 * Data provider for test_data_append_new_field_to_templates(). 2141 * 2142 * @return array of scenarios 2143 */ 2144 public function data_append_new_field_to_templates_provider(): array { 2145 return [ 2146 'Plain template' => [ 2147 'hasfield' => false, 2148 'hasotherfields' => false, 2149 'expected' => true, 2150 ], 2151 'Field already present' => [ 2152 'hasfield' => true, 2153 'hasotherfields' => false, 2154 'expected' => false, 2155 ], 2156 '##otherfields## tag present' => [ 2157 'hasfield' => false, 2158 'hasotherfields' => true, 2159 'expected' => false, 2160 ], 2161 'Field already present and ##otherfields## tag present' => [ 2162 'hasfield' => true, 2163 'hasotherfields' => true, 2164 'expected' => false, 2165 ], 2166 ]; 2167 } 2168 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body