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 namespace mod_data; 18 19 use externallib_advanced_testcase; 20 use mod_data_external; 21 use core_external\external_api; 22 use core_external\external_settings; 23 24 defined('MOODLE_INTERNAL') || die(); 25 26 global $CFG; 27 28 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 29 30 /** 31 * Database module external functions tests 32 * 33 * @package mod_data 34 * @category external 35 * @copyright 2015 Juan Leyva <juan@moodle.com> 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 * @since Moodle 2.9 38 * @coversDefaultClass \mod_data_external 39 */ 40 class externallib_test extends externallib_advanced_testcase { 41 42 /** @var stdClass Test module context. */ 43 protected $context; 44 45 /** @var stdClass Test course.*/ 46 protected $course; 47 48 /** @var stdClass Test course module. */ 49 protected $cm; 50 51 /** @var stdClass Test database activity. */ 52 protected $database; 53 54 /** @var stdClass Test group 1. */ 55 protected $group1; 56 57 /** @var stdClass Test group 2. */ 58 protected $group2; 59 60 /** @var stdClass Test student 1. */ 61 protected $student1; 62 63 /** @var stdClass Test student 2. */ 64 protected $student2; 65 66 /** @var stdClass Test student 3. */ 67 protected $student3; 68 69 /** @var stdClass Test student 4. */ 70 protected $student4; 71 72 /** @var stdClass Student role. */ 73 protected $studentrole; 74 75 /** @var stdClass Test teacher. */ 76 protected $teacher; 77 78 /** @var stdClass Teacher role. */ 79 protected $teacherrole; 80 81 /** 82 * Set up for every test 83 */ 84 public function setUp(): void { 85 global $DB; 86 $this->resetAfterTest(); 87 $this->setAdminUser(); 88 89 // Setup test data. 90 $course = new \stdClass(); 91 $course->groupmode = SEPARATEGROUPS; 92 $course->groupmodeforce = true; 93 $this->course = $this->getDataGenerator()->create_course($course); 94 $this->database = $this->getDataGenerator()->create_module('data', array('course' => $this->course->id)); 95 $this->context = \context_module::instance($this->database->cmid); 96 $this->cm = get_coursemodule_from_instance('data', $this->database->id); 97 98 // Create users. 99 $this->student1 = self::getDataGenerator()->create_user(['firstname' => 'Olivia', 'lastname' => 'Smith']); 100 $this->student2 = self::getDataGenerator()->create_user(['firstname' => 'Ezra', 'lastname' => 'Johnson']); 101 $this->student3 = self::getDataGenerator()->create_user(['firstname' => 'Amelia', 'lastname' => 'Williams']); 102 $this->teacher = self::getDataGenerator()->create_user(['firstname' => 'Asher', 'lastname' => 'Jones']); 103 104 // Users enrolments. 105 $this->studentrole = $DB->get_record('role', array('shortname' => 'student')); 106 $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 107 $this->getDataGenerator()->enrol_user($this->student1->id, $this->course->id, $this->studentrole->id, 'manual'); 108 $this->getDataGenerator()->enrol_user($this->student2->id, $this->course->id, $this->studentrole->id, 'manual'); 109 $this->getDataGenerator()->enrol_user($this->student3->id, $this->course->id, $this->studentrole->id, 'manual'); 110 $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual'); 111 112 $this->group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id)); 113 $this->group2 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id)); 114 groups_add_member($this->group1, $this->student1); 115 groups_add_member($this->group1, $this->student2); 116 groups_add_member($this->group2, $this->student3); 117 } 118 119 /** 120 * Add a test field to the database activity instance to be used in the unit tests. 121 * 122 * @return \data_field_base 123 */ 124 protected function add_test_field(): \data_field_base { 125 $generator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 126 127 // Add fields. 128 $fieldrecord = new \stdClass(); 129 $fieldrecord->name = 'Test field'; // Identifier of the records for testing. 130 $fieldrecord->type = 'text'; 131 return $generator->create_field($fieldrecord, $this->database); 132 } 133 134 /** 135 * Test get databases by courses 136 */ 137 public function test_mod_data_get_databases_by_courses() { 138 global $DB; 139 140 $this->resetAfterTest(true); 141 142 // Create users. 143 $student = self::getDataGenerator()->create_user(); 144 $teacher = self::getDataGenerator()->create_user(); 145 146 // Set to the student user. 147 self::setUser($student); 148 149 // Create courses to add the modules. 150 $course1 = self::getDataGenerator()->create_course(); 151 $course2 = self::getDataGenerator()->create_course(); 152 153 // First database. 154 $record = new \stdClass(); 155 $record->introformat = FORMAT_HTML; 156 $record->course = $course1->id; 157 // Set multilang text to check that is properly filtered to "en" only. 158 $record->name = '<span lang="en" class="multilang">English</span><span lang="es" class="multilang">EspaƱol</span>'; 159 $record->intro = '<button>Test with HTML allowed.</button>'; 160 $database1 = self::getDataGenerator()->create_module('data', $record); 161 162 // Second database. 163 $record = new \stdClass(); 164 $record->introformat = FORMAT_HTML; 165 $record->course = $course2->id; 166 $database2 = self::getDataGenerator()->create_module('data', $record); 167 168 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 169 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 170 171 // Users enrolments. 172 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 173 $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id, 'manual'); 174 175 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later. 176 $enrol = enrol_get_plugin('manual'); 177 $enrolinstances = enrol_get_instances($course2->id, true); 178 foreach ($enrolinstances as $courseenrolinstance) { 179 if ($courseenrolinstance->enrol == "manual") { 180 $instance2 = $courseenrolinstance; 181 break; 182 } 183 } 184 $enrol->enrol_user($instance2, $student->id, $studentrole->id); 185 186 // Enable multilang filter to on content and heading. 187 \filter_manager::reset_caches(); 188 filter_set_global_state('multilang', TEXTFILTER_ON); 189 filter_set_applies_to_strings('multilang', true); 190 // Set WS filtering. 191 $wssettings = external_settings::get_instance(); 192 $wssettings->set_filter(true); 193 194 // Create what we expect to be returned when querying the two courses. 195 // First for the student user. 196 $expectedfields = array('id', 'coursemodule', 'course', 'name', 'comments', 'timeavailablefrom', 197 'timeavailableto', 'timeviewfrom', 'timeviewto', 'requiredentries', 'requiredentriestoview', 198 'intro', 'introformat', 'introfiles', 'lang', 199 'maxentries', 'rssarticles', 'singletemplate', 'listtemplate', 200 'listtemplateheader', 'listtemplatefooter', 'addtemplate', 'rsstemplate', 'rsstitletemplate', 201 'csstemplate', 'jstemplate', 'asearchtemplate', 'approval', 202 'defaultsort', 'defaultsortdir', 'manageapproved'); 203 204 // Add expected coursemodule. 205 $database1->coursemodule = $database1->cmid; 206 $database1->introfiles = []; 207 $database1->lang = ''; 208 $database2->coursemodule = $database2->cmid; 209 $database2->introfiles = []; 210 $database2->lang = ''; 211 212 $expected1 = array(); 213 $expected2 = array(); 214 foreach ($expectedfields as $field) { 215 if ($field == 'approval' or $field == 'manageapproved') { 216 $database1->{$field} = (bool) $database1->{$field}; 217 $database2->{$field} = (bool) $database2->{$field}; 218 } 219 $expected1[$field] = $database1->{$field}; 220 $expected2[$field] = $database2->{$field}; 221 } 222 $expected1['name'] = 'English'; // Lang filtered expected. 223 $expected1['comments'] = (bool) $expected1['comments']; 224 $expected2['comments'] = (bool) $expected2['comments']; 225 226 $expecteddatabases = array(); 227 $expecteddatabases[] = $expected2; 228 $expecteddatabases[] = $expected1; 229 230 // Call the external function passing course ids. 231 $result = mod_data_external::get_databases_by_courses(array($course2->id, $course1->id)); 232 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result); 233 $this->assertEquals($expecteddatabases, $result['databases']); 234 235 // Call the external function without passing course id. 236 $result = mod_data_external::get_databases_by_courses(); 237 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result); 238 $this->assertEquals($expecteddatabases, $result['databases']); 239 240 // Unenrol user from second course and alter expected databases. 241 $enrol->unenrol_user($instance2, $student->id); 242 array_shift($expecteddatabases); 243 244 // Call the external function without passing course id. 245 $result = mod_data_external::get_databases_by_courses(); 246 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result); 247 $this->assertEquals($expecteddatabases, $result['databases']); 248 249 // Call for the second course we unenrolled the user from, expected warning. 250 $result = mod_data_external::get_databases_by_courses(array($course2->id)); 251 $this->assertCount(1, $result['warnings']); 252 $this->assertEquals('1', $result['warnings'][0]['warningcode']); 253 $this->assertEquals($course2->id, $result['warnings'][0]['itemid']); 254 255 // Now, try as a teacher for getting all the additional fields. 256 self::setUser($teacher); 257 258 $additionalfields = array('scale', 'assessed', 'assesstimestart', 'assesstimefinish', 'editany', 'notification', 'timemodified'); 259 260 foreach ($additionalfields as $field) { 261 if ($field == 'editany') { 262 $database1->{$field} = (bool) $database1->{$field}; 263 } 264 $expecteddatabases[0][$field] = $database1->{$field}; 265 } 266 $result = mod_data_external::get_databases_by_courses(); 267 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result); 268 $this->assertEquals($expecteddatabases, $result['databases']); 269 270 // Admin should get all the information. 271 self::setAdminUser(); 272 273 $result = mod_data_external::get_databases_by_courses(array($course1->id)); 274 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result); 275 $this->assertEquals($expecteddatabases, $result['databases']); 276 } 277 278 /** 279 * Test view_database invalid id. 280 */ 281 public function test_view_database_invalid_id() { 282 283 // Test invalid instance id. 284 $this->expectException('moodle_exception'); 285 mod_data_external::view_database(0); 286 } 287 288 /** 289 * Test view_database not enrolled user. 290 */ 291 public function test_view_database_not_enrolled_user() { 292 293 $usernotenrolled = self::getDataGenerator()->create_user(); 294 $this->setUser($usernotenrolled); 295 296 $this->expectException('moodle_exception'); 297 mod_data_external::view_database(0); 298 } 299 300 /** 301 * Test view_database no capabilities. 302 */ 303 public function test_view_database_no_capabilities() { 304 // Test user with no capabilities. 305 // We need a explicit prohibit since this capability is allowed for students by default. 306 assign_capability('mod/data:view', CAP_PROHIBIT, $this->studentrole->id, $this->context->id); 307 accesslib_clear_all_caches_for_unit_testing(); 308 309 $this->expectException('moodle_exception'); 310 mod_data_external::view_database(0); 311 } 312 313 /** 314 * Test view_database. 315 */ 316 public function test_view_database() { 317 318 // Test user with full capabilities. 319 $this->setUser($this->student1); 320 321 // Trigger and capture the event. 322 $sink = $this->redirectEvents(); 323 324 $result = mod_data_external::view_database($this->database->id); 325 $result = external_api::clean_returnvalue(mod_data_external::view_database_returns(), $result); 326 327 $events = $sink->get_events(); 328 $this->assertCount(1, $events); 329 $event = array_shift($events); 330 331 // Checking that the event contains the expected values. 332 $this->assertInstanceOf('\mod_data\event\course_module_viewed', $event); 333 $this->assertEquals($this->context, $event->get_context()); 334 $moodledata = new \moodle_url('/mod/data/view.php', array('id' => $this->cm->id)); 335 $this->assertEquals($moodledata, $event->get_url()); 336 $this->assertEventContextNotUsed($event); 337 $this->assertNotEmpty($event->get_name()); 338 } 339 340 /** 341 * Test get_data_access_information for student. 342 */ 343 public function test_get_data_access_information_student() { 344 global $DB; 345 346 // Add a field to database to let users add new entries. 347 $this->add_test_field(); 348 349 // Modify the database to add access restrictions. 350 $this->database->timeavailablefrom = time() + DAYSECS; 351 $this->database->requiredentries = 2; 352 $this->database->requiredentriestoview = 2; 353 $DB->update_record('data', $this->database); 354 355 // Test user with full capabilities. 356 $this->setUser($this->student1); 357 358 $result = mod_data_external::get_data_access_information($this->database->id); 359 $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result); 360 361 $this->assertEquals($this->group1->id, $result['groupid']); 362 363 $this->assertFalse($result['canmanageentries']); 364 $this->assertFalse($result['canapprove']); 365 $this->assertTrue($result['canaddentry']); // It return true because it doen't check time restrictions. 366 $this->assertFalse($result['timeavailable']); 367 $this->assertFalse($result['inreadonlyperiod']); 368 $this->assertEquals(0, $result['numentries']); 369 $this->assertEquals($this->database->requiredentries, $result['entrieslefttoadd']); 370 $this->assertEquals($this->database->requiredentriestoview, $result['entrieslefttoview']); 371 } 372 373 /** 374 * Test get_data_access_information for teacher. 375 */ 376 public function test_get_data_access_information_teacher() { 377 global $DB; 378 379 // Add a field to database to let users add new entries. 380 $this->add_test_field(); 381 382 // Modify the database to add access restrictions. 383 $this->database->timeavailablefrom = time() + DAYSECS; 384 $this->database->requiredentries = 2; 385 $this->database->requiredentriestoview = 2; 386 $DB->update_record('data', $this->database); 387 388 // Test user with full capabilities. 389 $this->setUser($this->teacher); 390 391 $result = mod_data_external::get_data_access_information($this->database->id); 392 $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result); 393 394 $this->assertEquals(0, $result['groupid']); 395 396 $this->assertTrue($result['canmanageentries']); 397 $this->assertTrue($result['canapprove']); 398 $this->assertTrue($result['canaddentry']); // It return true because it doen't check time restrictions. 399 $this->assertTrue($result['timeavailable']); 400 $this->assertFalse($result['inreadonlyperiod']); 401 $this->assertEquals(0, $result['numentries']); 402 $this->assertEquals(0, $result['entrieslefttoadd']); 403 $this->assertEquals(0, $result['entrieslefttoview']); 404 } 405 406 /** 407 * Test get_data_access_information with groups. 408 */ 409 public function test_get_data_access_information_groups() { 410 global $DB; 411 412 // Add a field to database to let users add new entries. 413 $this->add_test_field(); 414 415 $DB->set_field('course', 'groupmode', VISIBLEGROUPS, ['id' => $this->course->id]); 416 417 // Check I can see my group. 418 $this->setUser($this->student1); 419 420 $result = mod_data_external::get_data_access_information($this->database->id); 421 $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result); 422 423 $this->assertEquals($this->group1->id, $result['groupid']); // My group is correctly found. 424 $this->assertFalse($result['canmanageentries']); 425 $this->assertFalse($result['canapprove']); 426 $this->assertTrue($result['canaddentry']); // I can entries in my groups. 427 $this->assertTrue($result['timeavailable']); 428 $this->assertFalse($result['inreadonlyperiod']); 429 $this->assertEquals(0, $result['numentries']); 430 $this->assertEquals(0, $result['entrieslefttoadd']); 431 $this->assertEquals(0, $result['entrieslefttoview']); 432 433 // Check the other course group in visible groups mode. 434 $result = mod_data_external::get_data_access_information($this->database->id, $this->group2->id); 435 $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result); 436 437 $this->assertEquals($this->group2->id, $result['groupid']); // The group is correctly found. 438 $this->assertFalse($result['canmanageentries']); 439 $this->assertFalse($result['canapprove']); 440 $this->assertFalse($result['canaddentry']); // I cannot add entries in other groups. 441 $this->assertTrue($result['timeavailable']); 442 $this->assertFalse($result['inreadonlyperiod']); 443 $this->assertEquals(0, $result['numentries']); 444 $this->assertEquals(0, $result['entrieslefttoadd']); 445 $this->assertEquals(0, $result['entrieslefttoview']); 446 } 447 448 /** 449 * Helper method to populate the database with some entries. 450 * 451 * @return array the entry ids created 452 */ 453 public function populate_database_with_entries() { 454 global $DB; 455 456 // Force approval. 457 $DB->set_field('data', 'approval', 1, array('id' => $this->database->id)); 458 $generator = $this->getDataGenerator()->get_plugin_generator('mod_data'); 459 $fieldtypes = array('checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url'); 460 461 $count = 1; 462 // Creating test Fields with default parameter values. 463 foreach ($fieldtypes as $fieldtype) { 464 $fieldname = 'field-' . $count; 465 $record = new \stdClass(); 466 $record->name = $fieldname; 467 $record->type = $fieldtype; 468 $record->required = 1; 469 470 $generator->create_field($record, $this->database); 471 $count++; 472 } 473 // Get all the fields created. 474 $fields = $DB->get_records('data_fields', array('dataid' => $this->database->id), 'id'); 475 476 // Populate with contents, creating a new entry. 477 $contents = array(); 478 $contents[] = array('opt1', 'opt2', 'opt3', 'opt4'); 479 $contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows. 480 $contents[] = 'menu1'; 481 $contents[] = array('multimenu1', 'multimenu2', 'multimenu3', 'multimenu4'); 482 $contents[] = '12345'; 483 $contents[] = 'radioopt1'; 484 $contents[] = 'text for testing'; 485 $contents[] = '<p>text area testing<br /></p>'; 486 $contents[] = array('example.url', 'sampleurl'); 487 $count = 0; 488 $fieldcontents = array(); 489 foreach ($fields as $fieldrecord) { 490 $fieldcontents[$fieldrecord->id] = $contents[$count++]; 491 } 492 493 $this->setUser($this->student1); 494 $entry11 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id, ['Cats', 'Dogs']); 495 $this->setUser($this->student2); 496 $entry12 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id, ['Cats']); 497 $entry13 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id); 498 // Entry not in group. 499 $entry14 = $generator->create_entry($this->database, $fieldcontents, 0); 500 501 $this->setUser($this->student3); 502 $entry21 = $generator->create_entry($this->database, $fieldcontents, $this->group2->id); 503 504 // Approve all except $entry13. 505 $DB->set_field('data_records', 'approved', 1, ['id' => $entry11]); 506 $DB->set_field('data_records', 'approved', 1, ['id' => $entry12]); 507 $DB->set_field('data_records', 'approved', 1, ['id' => $entry14]); 508 $DB->set_field('data_records', 'approved', 1, ['id' => $entry21]); 509 510 return [$entry11, $entry12, $entry13, $entry14, $entry21]; 511 } 512 513 /** 514 * Test get_entries 515 */ 516 public function test_get_entries() { 517 global $DB; 518 519 // Check the behaviour when the database has no entries. 520 $result = mod_data_external::get_entries($this->database->id); 521 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 522 $this->assertEmpty($result['entries']); 523 524 $result = mod_data_external::get_entries($this->database->id, 0, true); 525 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 526 $this->assertEmpty($result['entries']); 527 $this->assertEmpty($result['listviewcontents']); 528 529 // Add a few fields to the database. 530 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 531 532 // First of all, expect to see only my group entries (not other users in other groups ones). 533 // We may expect entries without group also. 534 $this->setUser($this->student1); 535 $result = mod_data_external::get_entries($this->database->id); 536 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 537 $this->assertCount(0, $result['warnings']); 538 $this->assertCount(3, $result['entries']); 539 $this->assertEquals(3, $result['totalcount']); 540 $this->assertEquals($entry11, $result['entries'][0]['id']); 541 $this->assertCount(2, $result['entries'][0]['tags']); 542 $this->assertEquals($this->student1->id, $result['entries'][0]['userid']); 543 $this->assertEquals($this->group1->id, $result['entries'][0]['groupid']); 544 $this->assertEquals($this->database->id, $result['entries'][0]['dataid']); 545 $this->assertEquals($entry12, $result['entries'][1]['id']); 546 $this->assertCount(1, $result['entries'][1]['tags']); 547 $this->assertEquals('Cats', $result['entries'][1]['tags'][0]['rawname']); 548 $this->assertEquals($this->student2->id, $result['entries'][1]['userid']); 549 $this->assertEquals($this->group1->id, $result['entries'][1]['groupid']); 550 $this->assertEquals($this->database->id, $result['entries'][1]['dataid']); 551 $this->assertEquals($entry14, $result['entries'][2]['id']); 552 $this->assertEquals($this->student2->id, $result['entries'][2]['userid']); 553 $this->assertEquals(0, $result['entries'][2]['groupid']); 554 $this->assertEquals($this->database->id, $result['entries'][2]['dataid']); 555 // Other user in same group. 556 $this->setUser($this->student2); 557 $result = mod_data_external::get_entries($this->database->id); 558 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 559 $this->assertCount(0, $result['warnings']); 560 $this->assertCount(4, $result['entries']); // I can see my entry is pending approval. 561 $this->assertEquals(4, $result['totalcount']); 562 563 // Now try with the user in the second group that must see only two entries (his group entry and the one without group). 564 $this->setUser($this->student3); 565 $result = mod_data_external::get_entries($this->database->id); 566 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 567 $this->assertCount(0, $result['warnings']); 568 $this->assertCount(2, $result['entries']); 569 $this->assertEquals(2, $result['totalcount']); 570 $this->assertEquals($entry14, $result['entries'][0]['id']); 571 $this->assertEquals($this->student2->id, $result['entries'][0]['userid']); 572 $this->assertEquals(0, $result['entries'][0]['groupid']); 573 $this->assertEquals($this->database->id, $result['entries'][0]['dataid']); 574 $this->assertEquals($entry21, $result['entries'][1]['id']); 575 $this->assertEquals($this->student3->id, $result['entries'][1]['userid']); 576 $this->assertEquals($this->group2->id, $result['entries'][1]['groupid']); 577 $this->assertEquals($this->database->id, $result['entries'][1]['dataid']); 578 579 // Now, as teacher we should see all (we have permissions to view all groups). 580 $this->setUser($this->teacher); 581 $result = mod_data_external::get_entries($this->database->id); 582 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 583 $this->assertCount(0, $result['warnings']); 584 $this->assertCount(5, $result['entries']); // I can see the not approved one. 585 $this->assertEquals(5, $result['totalcount']); 586 587 $entries = $DB->get_records('data_records', array('dataid' => $this->database->id), 'id'); 588 $this->assertCount(5, $entries); 589 $count = 0; 590 foreach ($entries as $entry) { 591 $this->assertEquals($entry->id, $result['entries'][$count]['id']); 592 $count++; 593 } 594 595 // Basic test passing the parameter (instead having to calculate it). 596 $this->setUser($this->student1); 597 $result = mod_data_external::get_entries($this->database->id, $this->group1->id); 598 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 599 $this->assertCount(0, $result['warnings']); 600 $this->assertCount(3, $result['entries']); 601 $this->assertEquals(3, $result['totalcount']); 602 603 // Test ordering (reverse). 604 $this->setUser($this->student1); 605 $result = mod_data_external::get_entries($this->database->id, $this->group1->id, false, null, 'DESC'); 606 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 607 $this->assertCount(0, $result['warnings']); 608 $this->assertCount(3, $result['entries']); 609 $this->assertEquals(3, $result['totalcount']); 610 $this->assertEquals($entry14, $result['entries'][0]['id']); 611 612 // Test pagination. 613 $this->setUser($this->student1); 614 $result = mod_data_external::get_entries($this->database->id, $this->group1->id, false, null, null, 0, 1); 615 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 616 $this->assertCount(0, $result['warnings']); 617 $this->assertCount(1, $result['entries']); 618 $this->assertEquals(3, $result['totalcount']); 619 $this->assertEquals($entry11, $result['entries'][0]['id']); 620 621 $result = mod_data_external::get_entries($this->database->id, $this->group1->id, false, null, null, 1, 1); 622 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 623 $this->assertCount(0, $result['warnings']); 624 $this->assertCount(1, $result['entries']); 625 $this->assertEquals(3, $result['totalcount']); 626 $this->assertEquals($entry12, $result['entries'][0]['id']); 627 628 // Now test the return contents. 629 data_generate_default_template($this->database, 'listtemplate', 0, false, true); // Generate a default list template. 630 $result = mod_data_external::get_entries($this->database->id, $this->group1->id, true, null, null, 0, 2); 631 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result); 632 $this->assertCount(0, $result['warnings']); 633 $this->assertCount(2, $result['entries']); 634 $this->assertEquals(3, $result['totalcount']); 635 $this->assertCount(9, $result['entries'][0]['contents']); 636 $this->assertCount(9, $result['entries'][1]['contents']); 637 // Search for some content. 638 $this->assertTrue(strpos($result['listviewcontents'], 'opt1') !== false); 639 $this->assertTrue(strpos($result['listviewcontents'], 'January') !== false); 640 $this->assertTrue(strpos($result['listviewcontents'], 'menu1') !== false); 641 $this->assertTrue(strpos($result['listviewcontents'], 'text for testing') !== false); 642 $this->assertTrue(strpos($result['listviewcontents'], 'sampleurl') !== false); 643 } 644 645 /** 646 * Test get_entry_visible_groups. 647 */ 648 public function test_get_entry_visible_groups() { 649 global $DB; 650 651 $DB->set_field('course', 'groupmode', VISIBLEGROUPS, ['id' => $this->course->id]); 652 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 653 654 // Check I can see my approved group entries. 655 $this->setUser($this->student1); 656 $result = mod_data_external::get_entry($entry11); 657 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 658 $this->assertCount(0, $result['warnings']); 659 $this->assertEquals($entry11, $result['entry']['id']); 660 $this->assertTrue($result['entry']['approved']); 661 $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it. 662 663 // Entry from other group. 664 $result = mod_data_external::get_entry($entry21); 665 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 666 $this->assertCount(0, $result['warnings']); 667 $this->assertEquals($entry21, $result['entry']['id']); 668 } 669 670 /** 671 * Test get_entry_separated_groups. 672 */ 673 public function test_get_entry_separated_groups() { 674 global $DB; 675 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 676 677 // Check I can see my approved group entries. 678 $this->setUser($this->student1); 679 $result = mod_data_external::get_entry($entry11); 680 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 681 $this->assertCount(0, $result['warnings']); 682 $this->assertEquals($entry11, $result['entry']['id']); 683 $this->assertTrue($result['entry']['approved']); 684 $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it. 685 686 // Retrieve contents. 687 data_generate_default_template($this->database, 'singletemplate', 0, false, true); 688 $result = mod_data_external::get_entry($entry11, true); 689 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 690 $this->assertCount(0, $result['warnings']); 691 $this->assertCount(9, $result['entry']['contents']); 692 $this->assertTrue(strpos($result['entryviewcontents'], 'opt1') !== false); 693 $this->assertTrue(strpos($result['entryviewcontents'], 'January') !== false); 694 $this->assertTrue(strpos($result['entryviewcontents'], 'menu1') !== false); 695 $this->assertTrue(strpos($result['entryviewcontents'], 'text for testing') !== false); 696 $this->assertTrue(strpos($result['entryviewcontents'], 'sampleurl') !== false); 697 698 // This is in my group but I'm not the author. 699 $result = mod_data_external::get_entry($entry12); 700 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 701 $this->assertCount(0, $result['warnings']); 702 $this->assertEquals($entry12, $result['entry']['id']); 703 $this->assertTrue($result['entry']['approved']); 704 $this->assertFalse($result['entry']['canmanageentry']); // Not mine. 705 706 $this->setUser($this->student3); 707 $result = mod_data_external::get_entry($entry21); 708 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 709 $this->assertCount(0, $result['warnings']); 710 $this->assertEquals($entry21, $result['entry']['id']); 711 $this->assertTrue($result['entry']['approved']); 712 $this->assertTrue($result['entry']['canmanageentry']); // Is mine, I can manage it. 713 714 // As teacher I should be able to see all the entries. 715 $this->setUser($this->teacher); 716 $result = mod_data_external::get_entry($entry11); 717 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 718 $this->assertEquals($entry11, $result['entry']['id']); 719 720 $result = mod_data_external::get_entry($entry12); 721 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 722 $this->assertEquals($entry12, $result['entry']['id']); 723 // This is the not approved one. 724 $result = mod_data_external::get_entry($entry13); 725 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 726 $this->assertEquals($entry13, $result['entry']['id']); 727 728 $result = mod_data_external::get_entry($entry21); 729 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 730 $this->assertEquals($entry21, $result['entry']['id']); 731 732 // Now, try to get a pending approval. 733 $this->setUser($this->student1); 734 $this->expectException('moodle_exception'); 735 $result = mod_data_external::get_entry($entry13); 736 } 737 738 /** 739 * Test get_entry from other group in separated groups. 740 */ 741 public function test_get_entry_other_group_separated_groups() { 742 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 743 744 // We should not be able to view other gropu entries (in separated groups). 745 $this->setUser($this->student1); 746 $this->expectException('moodle_exception'); 747 $result = mod_data_external::get_entry($entry21); 748 } 749 750 /** 751 * Test get_fields. 752 */ 753 public function test_get_fields() { 754 global $DB; 755 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 756 757 $this->setUser($this->student1); 758 $result = mod_data_external::get_fields($this->database->id); 759 $result = external_api::clean_returnvalue(mod_data_external::get_fields_returns(), $result); 760 761 // Basically compare we retrieve all the fields and the correct values. 762 $fields = $DB->get_records('data_fields', array('dataid' => $this->database->id), 'id'); 763 foreach ($result['fields'] as $field) { 764 $this->assertEquals($field, (array) $fields[$field['id']]); 765 } 766 } 767 768 /** 769 * Test get_fields_database_without_fields. 770 */ 771 public function test_get_fields_database_without_fields() { 772 773 $this->setUser($this->student1); 774 $result = mod_data_external::get_fields($this->database->id); 775 $result = external_api::clean_returnvalue(mod_data_external::get_fields_returns(), $result); 776 777 $this->assertEmpty($result['fields']); 778 } 779 780 /** 781 * Test search_entries. 782 */ 783 public function test_search_entries() { 784 global $DB; 785 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 786 787 $this->setUser($this->student1); 788 // Empty search, it should return all the visible entries. 789 $result = mod_data_external::search_entries($this->database->id, 0, false); 790 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 791 $this->assertCount(3, $result['entries']); 792 $this->assertEquals(3, $result['totalcount']); 793 794 // Search for something that does not exists. 795 $result = mod_data_external::search_entries($this->database->id, 0, false, 'abc'); 796 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 797 $this->assertCount(0, $result['entries']); 798 $this->assertEquals(0, $result['totalcount']); 799 800 // Search by text matching all the entries. 801 $result = mod_data_external::search_entries($this->database->id, 0, false, 'text'); 802 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 803 $this->assertCount(3, $result['entries']); 804 $this->assertEquals(3, $result['totalcount']); 805 $this->assertEquals(3, $result['maxcount']); 806 807 // Now as the other student I should receive my not approved entry. Apply ordering here. 808 $this->setUser($this->student2); 809 $result = mod_data_external::search_entries($this->database->id, 0, false, 'text', [], DATA_APPROVED, 'ASC'); 810 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 811 $this->assertCount(4, $result['entries']); 812 $this->assertEquals(4, $result['totalcount']); 813 $this->assertEquals(4, $result['maxcount']); 814 // The not approved one should be the first. 815 $this->assertEquals($entry13, $result['entries'][0]['id']); 816 817 // Now as the other group student. 818 $this->setUser($this->student3); 819 $result = mod_data_external::search_entries($this->database->id, 0, false, 'text'); 820 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 821 $this->assertCount(2, $result['entries']); 822 $this->assertEquals(2, $result['totalcount']); 823 $this->assertEquals(2, $result['maxcount']); 824 $this->assertEquals($this->student2->id, $result['entries'][0]['userid']); 825 $this->assertEquals($this->student3->id, $result['entries'][1]['userid']); 826 827 // Same normal text search as teacher. 828 $this->setUser($this->teacher); 829 $result = mod_data_external::search_entries($this->database->id, 0, false, 'text'); 830 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 831 $this->assertCount(5, $result['entries']); // I can see all groups and non approved. 832 $this->assertEquals(5, $result['totalcount']); 833 $this->assertEquals(5, $result['maxcount']); 834 835 // Pagination. 836 $this->setUser($this->teacher); 837 $result = mod_data_external::search_entries($this->database->id, 0, false, 'text', [], DATA_TIMEADDED, 'ASC', 0, 2); 838 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 839 $this->assertCount(2, $result['entries']); // Only 2 per page. 840 $this->assertEquals(5, $result['totalcount']); 841 $this->assertEquals(5, $result['maxcount']); 842 843 // Now advanced search or not dinamic fields (user firstname for example). 844 $this->setUser($this->student1); 845 $advsearch = [ 846 ['name' => 'fn', 'value' => json_encode($this->student2->firstname)] 847 ]; 848 $result = mod_data_external::search_entries($this->database->id, 0, false, '', $advsearch); 849 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 850 $this->assertCount(2, $result['entries']); 851 $this->assertEquals(2, $result['totalcount']); 852 $this->assertEquals(3, $result['maxcount']); 853 $this->assertEquals($this->student2->id, $result['entries'][0]['userid']); // I only found mine! 854 855 // Advanced search for fields. 856 $field = $DB->get_record('data_fields', array('type' => 'url')); 857 $advsearch = [ 858 ['name' => 'f_' . $field->id , 'value' => 'sampleurl'] 859 ]; 860 $result = mod_data_external::search_entries($this->database->id, 0, false, '', $advsearch); 861 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 862 $this->assertCount(3, $result['entries']); // Found two entries matching this. 863 $this->assertEquals(3, $result['totalcount']); 864 $this->assertEquals(3, $result['maxcount']); 865 866 // Combined search. 867 $field2 = $DB->get_record('data_fields', array('type' => 'number')); 868 $advsearch = [ 869 ['name' => 'f_' . $field->id , 'value' => 'sampleurl'], 870 ['name' => 'f_' . $field2->id , 'value' => '12345'], 871 ['name' => 'ln', 'value' => json_encode($this->student2->lastname)] 872 ]; 873 $result = mod_data_external::search_entries($this->database->id, 0, false, '', $advsearch); 874 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 875 $this->assertCount(2, $result['entries']); // Only one matching everything. 876 $this->assertEquals(2, $result['totalcount']); 877 $this->assertEquals(3, $result['maxcount']); 878 879 // Combined search (no results). 880 $field2 = $DB->get_record('data_fields', array('type' => 'number')); 881 $advsearch = [ 882 ['name' => 'f_' . $field->id , 'value' => 'sampleurl'], 883 ['name' => 'f_' . $field2->id , 'value' => '98780333'], // Non existent number. 884 ]; 885 $result = mod_data_external::search_entries($this->database->id, 0, false, '', $advsearch); 886 $result = external_api::clean_returnvalue(mod_data_external::search_entries_returns(), $result); 887 $this->assertCount(0, $result['entries']); // Only one matching everything. 888 $this->assertEquals(0, $result['totalcount']); 889 $this->assertEquals(3, $result['maxcount']); 890 } 891 892 /** 893 * Test approve_entry. 894 */ 895 public function test_approve_entry() { 896 global $DB; 897 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 898 899 $this->setUser($this->teacher); 900 $this->assertEquals(0, $DB->get_field('data_records', 'approved', array('id' => $entry13))); 901 $result = mod_data_external::approve_entry($entry13); 902 $result = external_api::clean_returnvalue(mod_data_external::approve_entry_returns(), $result); 903 $this->assertEquals(1, $DB->get_field('data_records', 'approved', array('id' => $entry13))); 904 } 905 906 /** 907 * Test unapprove_entry. 908 */ 909 public function test_unapprove_entry() { 910 global $DB; 911 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 912 913 $this->setUser($this->teacher); 914 $this->assertEquals(1, $DB->get_field('data_records', 'approved', array('id' => $entry11))); 915 $result = mod_data_external::approve_entry($entry11, false); 916 $result = external_api::clean_returnvalue(mod_data_external::approve_entry_returns(), $result); 917 $this->assertEquals(0, $DB->get_field('data_records', 'approved', array('id' => $entry11))); 918 } 919 920 /** 921 * Test approve_entry missing permissions. 922 */ 923 public function test_approve_entry_missing_permissions() { 924 global $DB; 925 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 926 927 $this->setUser($this->student1); 928 $this->expectException('moodle_exception'); 929 mod_data_external::approve_entry($entry13); 930 } 931 932 /** 933 * Test delete_entry as teacher. Check I can delete any entry. 934 */ 935 public function test_delete_entry_as_teacher() { 936 global $DB; 937 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 938 939 $this->setUser($this->teacher); 940 $result = mod_data_external::delete_entry($entry11); 941 $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result); 942 $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry11))); 943 944 // Entry in other group. 945 $result = mod_data_external::delete_entry($entry21); 946 $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result); 947 $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry21))); 948 } 949 950 /** 951 * Test delete_entry as student. Check I can delete my own entries. 952 */ 953 public function test_delete_entry_as_student() { 954 global $DB; 955 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 956 957 $this->setUser($this->student1); 958 $result = mod_data_external::delete_entry($entry11); 959 $result = external_api::clean_returnvalue(mod_data_external::delete_entry_returns(), $result); 960 $this->assertEquals(0, $DB->count_records('data_records', array('id' => $entry11))); 961 } 962 963 /** 964 * Test delete_entry as student in read only mode period. Check I cannot delete my own entries in that period. 965 */ 966 public function test_delete_entry_as_student_in_read_only_period() { 967 global $DB; 968 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 969 // Set a time period. 970 $this->database->timeviewfrom = time() - HOURSECS; 971 $this->database->timeviewto = time() + HOURSECS; 972 $DB->update_record('data', $this->database); 973 974 $this->setUser($this->student1); 975 $this->expectException('moodle_exception'); 976 mod_data_external::delete_entry($entry11); 977 } 978 979 /** 980 * Test delete_entry with an user missing permissions. 981 */ 982 public function test_delete_entry_missing_permissions() { 983 global $DB; 984 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 985 986 $this->setUser($this->student1); 987 $this->expectException('moodle_exception'); 988 mod_data_external::delete_entry($entry21); 989 } 990 991 /** 992 * Test add_entry. 993 */ 994 public function test_add_entry() { 995 global $DB; 996 // First create the record structure and add some entries. 997 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 998 999 $this->setUser($this->student1); 1000 $newentrydata = []; 1001 $fields = $DB->get_records('data_fields', array('dataid' => $this->database->id), 'id'); 1002 // Prepare the new entry data. 1003 foreach ($fields as $field) { 1004 $subfield = $value = ''; 1005 1006 switch ($field->type) { 1007 case 'checkbox': 1008 $value = ['opt1', 'opt2']; 1009 break; 1010 case 'date': 1011 // Add two extra. 1012 $newentrydata[] = [ 1013 'fieldid' => $field->id, 1014 'subfield' => 'day', 1015 'value' => json_encode('5') 1016 ]; 1017 $newentrydata[] = [ 1018 'fieldid' => $field->id, 1019 'subfield' => 'month', 1020 'value' => json_encode('1') 1021 ]; 1022 $subfield = 'year'; 1023 $value = '1981'; 1024 break; 1025 case 'menu': 1026 $value = 'menu1'; 1027 break; 1028 case 'multimenu': 1029 $value = ['multimenu1', 'multimenu4']; 1030 break; 1031 case 'number': 1032 $value = 6; 1033 break; 1034 case 'radiobutton': 1035 $value = 'radioopt1'; 1036 break; 1037 case 'text': 1038 $value = 'some text'; 1039 break; 1040 case 'textarea': 1041 $newentrydata[] = [ 1042 'fieldid' => $field->id, 1043 'subfield' => 'content1', 1044 'value' => json_encode(FORMAT_MOODLE) 1045 ]; 1046 $newentrydata[] = [ 1047 'fieldid' => $field->id, 1048 'subfield' => 'itemid', 1049 'value' => json_encode(0) 1050 ]; 1051 $value = 'more text'; 1052 break; 1053 case 'url': 1054 $value = 'https://moodle.org'; 1055 $subfield = 0; 1056 break; 1057 } 1058 1059 $newentrydata[] = [ 1060 'fieldid' => $field->id, 1061 'subfield' => $subfield, 1062 'value' => json_encode($value) 1063 ]; 1064 } 1065 $result = mod_data_external::add_entry($this->database->id, 0, $newentrydata); 1066 $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result); 1067 1068 $newentryid = $result['newentryid']; 1069 $result = mod_data_external::get_entry($newentryid, true); 1070 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 1071 $this->assertEquals($this->student1->id, $result['entry']['userid']); 1072 $this->assertCount(9, $result['entry']['contents']); 1073 foreach ($result['entry']['contents'] as $content) { 1074 $field = $fields[$content['fieldid']]; 1075 // Stored content same that the one retrieved by WS. 1076 $dbcontent = $DB->get_record('data_content', array('fieldid' => $field->id, 'recordid' => $newentryid)); 1077 $this->assertEquals($dbcontent->content, $content['content']); 1078 1079 // Now double check everything stored is correct. 1080 if ($field->type == 'checkbox') { 1081 $this->assertEquals('opt1##opt2', $content['content']); 1082 continue; 1083 } 1084 if ($field->type == 'date') { 1085 $this->assertEquals(347500800, $content['content']); // Date in gregorian format. 1086 continue; 1087 } 1088 if ($field->type == 'menu') { 1089 $this->assertEquals('menu1', $content['content']); 1090 continue; 1091 } 1092 if ($field->type == 'multimenu') { 1093 $this->assertEquals('multimenu1##multimenu4', $content['content']); 1094 continue; 1095 } 1096 if ($field->type == 'number') { 1097 $this->assertEquals(6, $content['content']); 1098 continue; 1099 } 1100 if ($field->type == 'radiobutton') { 1101 $this->assertEquals('radioopt1', $content['content']); 1102 continue; 1103 } 1104 if ($field->type == 'text') { 1105 $this->assertEquals('some text', $content['content']); 1106 continue; 1107 } 1108 if ($field->type == 'textarea') { 1109 $this->assertEquals('more text', $content['content']); 1110 $this->assertEquals(FORMAT_MOODLE, $content['content1']); 1111 continue; 1112 } 1113 if ($field->type == 'url') { 1114 $this->assertEquals('https://moodle.org', $content['content']); 1115 continue; 1116 } 1117 $this->assertEquals('multimenu1##multimenu4', $content['content']); 1118 } 1119 1120 // Now, try to add another entry but removing some required data. 1121 unset($newentrydata[0]); 1122 $result = mod_data_external::add_entry($this->database->id, 0, $newentrydata); 1123 $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result); 1124 $this->assertEquals(0, $result['newentryid']); 1125 $this->assertCount(0, $result['generalnotifications']); 1126 $this->assertCount(1, $result['fieldnotifications']); 1127 $this->assertEquals('field-1', $result['fieldnotifications'][0]['fieldname']); 1128 $this->assertEquals(get_string('errormustsupplyvalue', 'data'), $result['fieldnotifications'][0]['notification']); 1129 } 1130 1131 /** 1132 * Test add_entry empty_form. 1133 */ 1134 public function test_add_entry_empty_form() { 1135 1136 // Add a field to database to let users add new entries. 1137 $this->add_test_field(); 1138 1139 $result = mod_data_external::add_entry($this->database->id, 0, []); 1140 $result = external_api::clean_returnvalue(mod_data_external::add_entry_returns(), $result); 1141 $this->assertEquals(0, $result['newentryid']); 1142 $this->assertCount(1, $result['generalnotifications']); 1143 $this->assertCount(0, $result['fieldnotifications']); 1144 $this->assertEquals(get_string('emptyaddform', 'data'), $result['generalnotifications'][0]); 1145 } 1146 1147 /** 1148 * Test add_entry read_only_period. 1149 */ 1150 public function test_add_entry_read_only_period() { 1151 global $DB; 1152 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 1153 // Set a time period. 1154 $this->database->timeviewfrom = time() - HOURSECS; 1155 $this->database->timeviewto = time() + HOURSECS; 1156 $DB->update_record('data', $this->database); 1157 1158 $this->setUser($this->student1); 1159 $this->expectExceptionMessage(get_string('noaccess', 'data')); 1160 $this->expectException('moodle_exception'); 1161 mod_data_external::add_entry($this->database->id, 0, []); 1162 } 1163 1164 /** 1165 * Test add_entry max_num_entries. 1166 */ 1167 public function test_add_entry_max_num_entries() { 1168 global $DB; 1169 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 1170 // Set a time period. 1171 $this->database->maxentries = 1; 1172 $DB->update_record('data', $this->database); 1173 1174 $this->setUser($this->student1); 1175 $this->expectExceptionMessage(get_string('noaccess', 'data')); 1176 $this->expectException('moodle_exception'); 1177 mod_data_external::add_entry($this->database->id, 0, []); 1178 } 1179 1180 /** 1181 * Test add_entry invalid group. 1182 */ 1183 public function test_add_entry_invalid_group() { 1184 1185 // Add a field to database to let users add new entries. 1186 $this->add_test_field(); 1187 1188 $this->setUser($this->student1); 1189 $this->expectExceptionMessage(get_string('noaccess', 'data')); 1190 $this->expectException('moodle_exception'); 1191 mod_data_external::add_entry($this->database->id, $this->group2->id, []); 1192 } 1193 1194 /** 1195 * Test add_entry for an empty database (no fields). 1196 * 1197 * @covers ::add_entry 1198 */ 1199 public function test_add_entry_empty_database() { 1200 $this->expectException('moodle_exception'); 1201 mod_data_external::add_entry($this->database->id, 0, []); 1202 } 1203 1204 /** 1205 * Test update_entry. 1206 */ 1207 public function test_update_entry() { 1208 global $DB; 1209 // First create the record structure and add some entries. 1210 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 1211 1212 $this->setUser($this->student1); 1213 $newentrydata = []; 1214 $fields = $DB->get_records('data_fields', array('dataid' => $this->database->id), 'id'); 1215 // Prepare the new entry data. 1216 foreach ($fields as $field) { 1217 $subfield = $value = ''; 1218 1219 switch ($field->type) { 1220 case 'checkbox': 1221 $value = ['opt1', 'opt2']; 1222 break; 1223 case 'date': 1224 // Add two extra. 1225 $newentrydata[] = [ 1226 'fieldid' => $field->id, 1227 'subfield' => 'day', 1228 'value' => json_encode('5') 1229 ]; 1230 $newentrydata[] = [ 1231 'fieldid' => $field->id, 1232 'subfield' => 'month', 1233 'value' => json_encode('1') 1234 ]; 1235 $subfield = 'year'; 1236 $value = '1981'; 1237 break; 1238 case 'menu': 1239 $value = 'menu1'; 1240 break; 1241 case 'multimenu': 1242 $value = ['multimenu1', 'multimenu4']; 1243 break; 1244 case 'number': 1245 $value = 6; 1246 break; 1247 case 'radiobutton': 1248 $value = 'radioopt2'; 1249 break; 1250 case 'text': 1251 $value = 'some text'; 1252 break; 1253 case 'textarea': 1254 $newentrydata[] = [ 1255 'fieldid' => $field->id, 1256 'subfield' => 'content1', 1257 'value' => json_encode(FORMAT_MOODLE) 1258 ]; 1259 $newentrydata[] = [ 1260 'fieldid' => $field->id, 1261 'subfield' => 'itemid', 1262 'value' => json_encode(0) 1263 ]; 1264 $value = 'more text'; 1265 break; 1266 case 'url': 1267 $value = 'https://moodle.org'; 1268 $subfield = 0; 1269 break; 1270 } 1271 1272 $newentrydata[] = [ 1273 'fieldid' => $field->id, 1274 'subfield' => $subfield, 1275 'value' => json_encode($value) 1276 ]; 1277 } 1278 $result = mod_data_external::update_entry($entry11, $newentrydata); 1279 $result = external_api::clean_returnvalue(mod_data_external::update_entry_returns(), $result); 1280 $this->assertTrue($result['updated']); 1281 $this->assertCount(0, $result['generalnotifications']); 1282 $this->assertCount(0, $result['fieldnotifications']); 1283 1284 $result = mod_data_external::get_entry($entry11, true); 1285 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 1286 $this->assertEquals($this->student1->id, $result['entry']['userid']); 1287 $this->assertCount(9, $result['entry']['contents']); 1288 foreach ($result['entry']['contents'] as $content) { 1289 $field = $fields[$content['fieldid']]; 1290 // Stored content same that the one retrieved by WS. 1291 $dbcontent = $DB->get_record('data_content', array('fieldid' => $field->id, 'recordid' => $entry11)); 1292 $this->assertEquals($dbcontent->content, $content['content']); 1293 1294 // Now double check everything stored is correct. 1295 if ($field->type == 'checkbox') { 1296 $this->assertEquals('opt1##opt2', $content['content']); 1297 continue; 1298 } 1299 if ($field->type == 'date') { 1300 $this->assertEquals(347500800, $content['content']); // Date in gregorian format. 1301 continue; 1302 } 1303 if ($field->type == 'menu') { 1304 $this->assertEquals('menu1', $content['content']); 1305 continue; 1306 } 1307 if ($field->type == 'multimenu') { 1308 $this->assertEquals('multimenu1##multimenu4', $content['content']); 1309 continue; 1310 } 1311 if ($field->type == 'number') { 1312 $this->assertEquals(6, $content['content']); 1313 continue; 1314 } 1315 if ($field->type == 'radiobutton') { 1316 $this->assertEquals('radioopt2', $content['content']); 1317 continue; 1318 } 1319 if ($field->type == 'text') { 1320 $this->assertEquals('some text', $content['content']); 1321 continue; 1322 } 1323 if ($field->type == 'textarea') { 1324 $this->assertEquals('more text', $content['content']); 1325 $this->assertEquals(FORMAT_MOODLE, $content['content1']); 1326 continue; 1327 } 1328 if ($field->type == 'url') { 1329 $this->assertEquals('https://moodle.org', $content['content']); 1330 continue; 1331 } 1332 $this->assertEquals('multimenu1##multimenu4', $content['content']); 1333 } 1334 1335 // Now, try to update the entry but removing some required data. 1336 unset($newentrydata[0]); 1337 $result = mod_data_external::update_entry($entry11, $newentrydata); 1338 $result = external_api::clean_returnvalue(mod_data_external::update_entry_returns(), $result); 1339 $this->assertFalse($result['updated']); 1340 $this->assertCount(0, $result['generalnotifications']); 1341 $this->assertCount(1, $result['fieldnotifications']); 1342 $this->assertEquals('field-1', $result['fieldnotifications'][0]['fieldname']); 1343 $this->assertEquals(get_string('errormustsupplyvalue', 'data'), $result['fieldnotifications'][0]['notification']); 1344 } 1345 1346 /** 1347 * Test update_entry sending empty data. 1348 */ 1349 public function test_update_entry_empty_data() { 1350 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 1351 1352 $this->setUser($this->student1); 1353 $result = mod_data_external::update_entry($entry11, []); 1354 $result = external_api::clean_returnvalue(mod_data_external::update_entry_returns(), $result); 1355 $this->assertFalse($result['updated']); 1356 $this->assertCount(1, $result['generalnotifications']); 1357 $this->assertCount(9, $result['fieldnotifications']); 1358 $this->assertEquals(get_string('emptyaddform', 'data'), $result['generalnotifications'][0]); 1359 } 1360 1361 /** 1362 * Test update_entry in read only period. 1363 */ 1364 public function test_update_entry_read_only_period() { 1365 global $DB; 1366 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 1367 // Set a time period. 1368 $this->database->timeviewfrom = time() - HOURSECS; 1369 $this->database->timeviewto = time() + HOURSECS; 1370 $DB->update_record('data', $this->database); 1371 1372 $this->setUser($this->student1); 1373 $this->expectExceptionMessage(get_string('noaccess', 'data')); 1374 $this->expectException('moodle_exception'); 1375 mod_data_external::update_entry($entry11, []); 1376 } 1377 1378 /** 1379 * Test update_entry other_user. 1380 */ 1381 public function test_update_entry_other_user() { 1382 // Try to update other user entry. 1383 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 1384 $this->setUser($this->student2); 1385 $this->expectExceptionMessage(get_string('noaccess', 'data')); 1386 $this->expectException('moodle_exception'); 1387 mod_data_external::update_entry($entry11, []); 1388 } 1389 1390 /** 1391 * Test get_entry_rating_information. 1392 */ 1393 public function test_get_entry_rating_information() { 1394 global $DB, $CFG; 1395 require_once($CFG->dirroot . '/rating/lib.php'); 1396 1397 $DB->set_field('data', 'assessed', RATING_AGGREGATE_SUM, array('id' => $this->database->id)); 1398 $DB->set_field('data', 'scale', 100, array('id' => $this->database->id)); 1399 list($entry11, $entry12, $entry13, $entry14, $entry21) = self::populate_database_with_entries(); 1400 1401 $user1 = self::getDataGenerator()->create_user(); 1402 $user2 = self::getDataGenerator()->create_user(); 1403 $this->getDataGenerator()->enrol_user($user1->id, $this->course->id, $this->studentrole->id, 'manual'); 1404 $this->getDataGenerator()->enrol_user($user2->id, $this->course->id, $this->studentrole->id, 'manual'); 1405 1406 // Rate the entry as user1. 1407 $rating1 = new \stdClass(); 1408 $rating1->contextid = $this->context->id; 1409 $rating1->component = 'mod_data'; 1410 $rating1->ratingarea = 'entry'; 1411 $rating1->itemid = $entry11; 1412 $rating1->rating = 50; 1413 $rating1->scaleid = 100; 1414 $rating1->userid = $user1->id; 1415 $rating1->timecreated = time(); 1416 $rating1->timemodified = time(); 1417 $rating1->id = $DB->insert_record('rating', $rating1); 1418 1419 // Rate the entry as user2. 1420 $rating2 = new \stdClass(); 1421 $rating2->contextid = $this->context->id; 1422 $rating2->component = 'mod_data'; 1423 $rating2->ratingarea = 'entry'; 1424 $rating2->itemid = $entry11; 1425 $rating2->rating = 100; 1426 $rating2->scaleid = 100; 1427 $rating2->userid = $user2->id; 1428 $rating2->timecreated = time() + 1; 1429 $rating2->timemodified = time() + 1; 1430 $rating2->id = $DB->insert_record('rating', $rating2); 1431 1432 // As student, retrieve ratings information. 1433 $this->setUser($this->student2); 1434 $result = mod_data_external::get_entry($entry11); 1435 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 1436 $this->assertCount(1, $result['ratinginfo']['ratings']); 1437 $this->assertFalse($result['ratinginfo']['ratings'][0]['canviewaggregate']); 1438 $this->assertFalse($result['ratinginfo']['canviewall']); 1439 $this->assertFalse($result['ratinginfo']['ratings'][0]['canrate']); 1440 $this->assertTrue(!isset($result['ratinginfo']['ratings'][0]['count'])); 1441 1442 // Now, as teacher, I should see the info correctly. 1443 $this->setUser($this->teacher); 1444 $result = mod_data_external::get_entry($entry11); 1445 $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); 1446 $this->assertCount(1, $result['ratinginfo']['ratings']); 1447 $this->assertTrue($result['ratinginfo']['ratings'][0]['canviewaggregate']); 1448 $this->assertTrue($result['ratinginfo']['canviewall']); 1449 $this->assertTrue($result['ratinginfo']['ratings'][0]['canrate']); 1450 $this->assertEquals(2, $result['ratinginfo']['ratings'][0]['count']); 1451 $this->assertEquals(100, $result['ratinginfo']['ratings'][0]['aggregate']); // Expect maximium scale value. 1452 } 1453 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body