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