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