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