Differences Between: [Versions 311 and 403] [Versions 400 and 403] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Feedback module external functions tests 19 * 20 * @package mod_feedback 21 * @category external 22 * @copyright 2017 Juan Leyva <juan@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 * @since Moodle 3.3 25 */ 26 27 namespace mod_feedback\external; 28 29 use core_external\external_api; 30 use externallib_advanced_testcase; 31 use feedback_item_multichoice; 32 use mod_feedback_external; 33 use moodle_exception; 34 35 defined('MOODLE_INTERNAL') || die(); 36 37 global $CFG; 38 39 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 40 require_once($CFG->dirroot . '/mod/feedback/lib.php'); 41 42 /** 43 * Feedback module external functions tests 44 * 45 * @package mod_feedback 46 * @category external 47 * @copyright 2017 Juan Leyva <juan@moodle.com> 48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 49 * @since Moodle 3.3 50 * @covers \mod_feedback_external 51 */ 52 class external_test extends externallib_advanced_testcase { 53 54 // TODO These should be removed. 55 // Testcase classes should not have any properties or store state. 56 protected $course; 57 protected $feedback; 58 protected $context; 59 protected $cm; 60 protected $student; 61 protected $teacher; 62 protected $studentrole; 63 protected $teacherrole; 64 65 /** 66 * Set up for every test 67 */ 68 public function setUp(): void { 69 global $DB; 70 $this->resetAfterTest(); 71 $this->setAdminUser(); 72 73 // Setup test data. 74 $this->course = $this->getDataGenerator()->create_course(); 75 $this->feedback = $this->getDataGenerator()->create_module('feedback', 76 array('course' => $this->course->id, 'email_notification' => 1)); 77 $this->context = \context_module::instance($this->feedback->cmid); 78 $this->cm = get_coursemodule_from_instance('feedback', $this->feedback->id); 79 80 // Create users. 81 $this->student = self::getDataGenerator()->create_user(); 82 $this->teacher = self::getDataGenerator()->create_user(); 83 84 // Users enrolments. 85 $this->studentrole = $DB->get_record('role', array('shortname' => 'student')); 86 $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 87 $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual'); 88 $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual'); 89 } 90 91 /** 92 * Helper method to add items to an existing feedback. 93 * 94 * @param \stdClass $feedback feedback instance 95 * @param integer $pagescount the number of pages we want in the feedback 96 * @return array list of items created 97 */ 98 public function populate_feedback($feedback, $pagescount = 1) { 99 $feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback'); 100 $itemscreated = []; 101 102 // Create at least one page. 103 $itemscreated[] = $feedbackgenerator->create_item_label($feedback); 104 $itemscreated[] = $feedbackgenerator->create_item_info($feedback); 105 $itemscreated[] = $feedbackgenerator->create_item_numeric($feedback); 106 107 // Check if we want more pages. 108 for ($i = 1; $i < $pagescount; $i++) { 109 $itemscreated[] = $feedbackgenerator->create_item_pagebreak($feedback); 110 $itemscreated[] = $feedbackgenerator->create_item_multichoice($feedback); 111 $itemscreated[] = $feedbackgenerator->create_item_multichoicerated($feedback); 112 $itemscreated[] = $feedbackgenerator->create_item_textarea($feedback); 113 $itemscreated[] = $feedbackgenerator->create_item_textfield($feedback); 114 $itemscreated[] = $feedbackgenerator->create_item_numeric($feedback); 115 } 116 return $itemscreated; 117 } 118 119 120 /** 121 * Test test_mod_feedback_get_feedbacks_by_courses 122 */ 123 public function test_mod_feedback_get_feedbacks_by_courses() { 124 125 // Create additional course. 126 $course2 = self::getDataGenerator()->create_course(); 127 128 // Second feedback. 129 $record = new \stdClass(); 130 $record->course = $course2->id; 131 $feedback2 = self::getDataGenerator()->create_module('feedback', $record); 132 133 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later. 134 $enrol = enrol_get_plugin('manual'); 135 $enrolinstances = enrol_get_instances($course2->id, true); 136 $instance2 = (object) []; 137 foreach ($enrolinstances as $courseenrolinstance) { 138 if ($courseenrolinstance->enrol == "manual") { 139 $instance2 = $courseenrolinstance; 140 break; 141 } 142 } 143 144 $enrol->enrol_user($instance2, $this->student->id, $this->studentrole->id); 145 146 self::setUser($this->student); 147 148 $returndescription = mod_feedback_external::get_feedbacks_by_courses_returns(); 149 150 // Create what we expect to be returned when querying the two courses. 151 // First for the student user. 152 $expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang', 'anonymous', 153 'multiple_submit', 'autonumbering', 'page_after_submitformat', 'publish_stats', 'completionsubmit'); 154 155 $properties = feedback_summary_exporter::read_properties_definition(); 156 157 // Add expected coursemodule and data. 158 $feedback1 = $this->feedback; 159 $feedback1->coursemodule = $feedback1->cmid; 160 $feedback1->introformat = 1; 161 $feedback1->introfiles = []; 162 $feedback1->lang = ''; 163 164 $feedback2->coursemodule = $feedback2->cmid; 165 $feedback2->introformat = 1; 166 $feedback2->introfiles = []; 167 $feedback2->lang = ''; 168 169 foreach ($expectedfields as $field) { 170 if (!empty($properties[$field]) && $properties[$field]['type'] == PARAM_BOOL) { 171 $feedback1->{$field} = (bool) $feedback1->{$field}; 172 $feedback2->{$field} = (bool) $feedback2->{$field}; 173 } 174 $expected1[$field] = $feedback1->{$field}; 175 $expected2[$field] = $feedback2->{$field}; 176 } 177 178 $expectedfeedbacks = array($expected2, $expected1); 179 180 // Call the external function passing course ids. 181 $result = mod_feedback_external::get_feedbacks_by_courses(array($course2->id, $this->course->id)); 182 $result = external_api::clean_returnvalue($returndescription, $result); 183 184 $this->assertEquals($expectedfeedbacks, $result['feedbacks']); 185 $this->assertCount(0, $result['warnings']); 186 187 // Call the external function without passing course id. 188 $result = mod_feedback_external::get_feedbacks_by_courses(); 189 $result = external_api::clean_returnvalue($returndescription, $result); 190 $this->assertEquals($expectedfeedbacks, $result['feedbacks']); 191 $this->assertCount(0, $result['warnings']); 192 193 // Unenrol user from second course and alter expected feedbacks. 194 $enrol->unenrol_user($instance2, $this->student->id); 195 array_shift($expectedfeedbacks); 196 197 // Call the external function without passing course id. 198 $result = mod_feedback_external::get_feedbacks_by_courses(); 199 $result = external_api::clean_returnvalue($returndescription, $result); 200 $this->assertEquals($expectedfeedbacks, $result['feedbacks']); 201 202 // Call for the second course we unenrolled the user from, expected warning. 203 $result = mod_feedback_external::get_feedbacks_by_courses(array($course2->id)); 204 $this->assertCount(1, $result['warnings']); 205 $this->assertEquals('1', $result['warnings'][0]['warningcode']); 206 $this->assertEquals($course2->id, $result['warnings'][0]['itemid']); 207 208 // Now, try as a teacher for getting all the additional fields. 209 self::setUser($this->teacher); 210 211 $additionalfields = array('email_notification', 'site_after_submit', 'page_after_submit', 'timeopen', 'timeclose', 212 'timemodified', 'pageaftersubmitfiles'); 213 214 $feedback1->pageaftersubmitfiles = []; 215 216 foreach ($additionalfields as $field) { 217 if (!empty($properties[$field]) && $properties[$field]['type'] == PARAM_BOOL) { 218 $feedback1->{$field} = (bool) $feedback1->{$field}; 219 } 220 $expectedfeedbacks[0][$field] = $feedback1->{$field}; 221 } 222 $expectedfeedbacks[0]['page_after_submitformat'] = 1; 223 224 $result = mod_feedback_external::get_feedbacks_by_courses(); 225 $result = external_api::clean_returnvalue($returndescription, $result); 226 $this->assertEquals($expectedfeedbacks, $result['feedbacks']); 227 228 // Admin also should get all the information. 229 self::setAdminUser(); 230 231 $result = mod_feedback_external::get_feedbacks_by_courses(array($this->course->id)); 232 $result = external_api::clean_returnvalue($returndescription, $result); 233 $this->assertEquals($expectedfeedbacks, $result['feedbacks']); 234 } 235 236 /** 237 * Test get_feedback_access_information function with basic defaults for student. 238 */ 239 public function test_get_feedback_access_information_student() { 240 241 self::setUser($this->student); 242 $result = mod_feedback_external::get_feedback_access_information($this->feedback->id); 243 $result = external_api::clean_returnvalue(mod_feedback_external::get_feedback_access_information_returns(), $result); 244 245 $this->assertFalse($result['canviewanalysis']); 246 $this->assertFalse($result['candeletesubmissions']); 247 $this->assertFalse($result['canviewreports']); 248 $this->assertFalse($result['canedititems']); 249 $this->assertTrue($result['cancomplete']); 250 $this->assertTrue($result['cansubmit']); 251 $this->assertTrue($result['isempty']); 252 $this->assertTrue($result['isopen']); 253 $this->assertTrue($result['isanonymous']); 254 $this->assertFalse($result['isalreadysubmitted']); 255 } 256 257 /** 258 * Test get_feedback_access_information function with basic defaults for teacher. 259 */ 260 public function test_get_feedback_access_information_teacher() { 261 262 self::setUser($this->teacher); 263 $result = mod_feedback_external::get_feedback_access_information($this->feedback->id); 264 $result = external_api::clean_returnvalue(mod_feedback_external::get_feedback_access_information_returns(), $result); 265 266 $this->assertTrue($result['canviewanalysis']); 267 $this->assertTrue($result['canviewreports']); 268 $this->assertTrue($result['canedititems']); 269 $this->assertTrue($result['candeletesubmissions']); 270 $this->assertFalse($result['cancomplete']); 271 $this->assertTrue($result['cansubmit']); 272 $this->assertTrue($result['isempty']); 273 $this->assertTrue($result['isopen']); 274 $this->assertTrue($result['isanonymous']); 275 $this->assertFalse($result['isalreadysubmitted']); 276 277 // Add some items to the feedback and check is not empty any more. 278 self::populate_feedback($this->feedback); 279 $result = mod_feedback_external::get_feedback_access_information($this->feedback->id); 280 $result = external_api::clean_returnvalue(mod_feedback_external::get_feedback_access_information_returns(), $result); 281 $this->assertFalse($result['isempty']); 282 } 283 284 /** 285 * Test view_feedback invalid id. 286 */ 287 public function test_view_feedback_invalid_id() { 288 // Test invalid instance id. 289 $this->expectException(moodle_exception::class); 290 mod_feedback_external::view_feedback(0); 291 } 292 /** 293 * Test view_feedback not enrolled user. 294 */ 295 public function test_view_feedback_not_enrolled_user() { 296 $usernotenrolled = self::getDataGenerator()->create_user(); 297 $this->setUser($usernotenrolled); 298 $this->expectException(moodle_exception::class); 299 mod_feedback_external::view_feedback(0); 300 } 301 /** 302 * Test view_feedback no capabilities. 303 */ 304 public function test_view_feedback_no_capabilities() { 305 // Test user with no capabilities. 306 // We need a explicit prohibit since this capability is allowed for students by default. 307 assign_capability('mod/feedback:view', CAP_PROHIBIT, $this->studentrole->id, $this->context->id); 308 accesslib_clear_all_caches_for_unit_testing(); 309 $this->expectException(moodle_exception::class); 310 mod_feedback_external::view_feedback(0); 311 } 312 /** 313 * Test view_feedback. 314 */ 315 public function test_view_feedback() { 316 // Test user with full capabilities. 317 $this->setUser($this->student); 318 // Trigger and capture the event. 319 $sink = $this->redirectEvents(); 320 $result = mod_feedback_external::view_feedback($this->feedback->id); 321 $result = external_api::clean_returnvalue(mod_feedback_external::view_feedback_returns(), $result); 322 $events = $sink->get_events(); 323 $this->assertCount(1, $events); 324 $event = array_shift($events); 325 // Checking that the event contains the expected values. 326 $this->assertInstanceOf('\mod_feedback\event\course_module_viewed', $event); 327 $this->assertEquals($this->context, $event->get_context()); 328 $moodledata = new \moodle_url('/mod/feedback/view.php', array('id' => $this->cm->id)); 329 $this->assertEquals($moodledata, $event->get_url()); 330 $this->assertEventContextNotUsed($event); 331 $this->assertNotEmpty($event->get_name()); 332 } 333 334 /** 335 * Test get_current_completed_tmp. 336 */ 337 public function test_get_current_completed_tmp() { 338 global $DB; 339 340 // Force non anonymous. 341 $DB->set_field('feedback', 'anonymous', FEEDBACK_ANONYMOUS_NO, array('id' => $this->feedback->id)); 342 // Add a completed_tmp record. 343 $record = [ 344 'feedback' => $this->feedback->id, 345 'userid' => $this->student->id, 346 'guestid' => '', 347 'timemodified' => time() - DAYSECS, 348 'random_response' => 0, 349 'anonymous_response' => FEEDBACK_ANONYMOUS_NO, 350 'courseid' => $this->course->id, 351 ]; 352 $record['id'] = $DB->insert_record('feedback_completedtmp', (object) $record); 353 354 // Test user with full capabilities. 355 $this->setUser($this->student); 356 357 $result = mod_feedback_external::get_current_completed_tmp($this->feedback->id); 358 $result = external_api::clean_returnvalue(mod_feedback_external::get_current_completed_tmp_returns(), $result); 359 $this->assertEquals($record['id'], $result['feedback']['id']); 360 } 361 362 /** 363 * Test get_items. 364 */ 365 public function test_get_items() { 366 // Test user with full capabilities. 367 $this->setUser($this->student); 368 369 // Add questions to the feedback, we are adding 2 pages of questions. 370 $itemscreated = self::populate_feedback($this->feedback, 2); 371 372 $result = mod_feedback_external::get_items($this->feedback->id); 373 $result = external_api::clean_returnvalue(mod_feedback_external::get_items_returns(), $result); 374 $this->assertCount(count($itemscreated), $result['items']); 375 $index = 1; 376 foreach ($result['items'] as $key => $item) { 377 if (is_numeric($itemscreated[$key])) { 378 continue; // Page break. 379 } 380 // Cannot compare directly the exporter and the db object (exporter have more fields). 381 $this->assertEquals($itemscreated[$key]->id, $item['id']); 382 $this->assertEquals($itemscreated[$key]->typ, $item['typ']); 383 $this->assertEquals($itemscreated[$key]->name, $item['name']); 384 $this->assertEquals($itemscreated[$key]->label, $item['label']); 385 386 if ($item['hasvalue']) { 387 $this->assertEquals($index, $item['itemnumber']); 388 $index++; 389 } 390 } 391 } 392 393 /** 394 * Test get_items, to confirm validation is done too. 395 * 396 * @dataProvider items_provider 397 * @param string $role Whether the current user should be a student or a teacher. 398 * @param array $info Settings to create the feedback. 399 * @param string|null $warning The warning message to display or null if warnings result is empty. 400 */ 401 public function test_get_items_validation(string $role, array $info, ?string $warning): void { 402 global $DB; 403 404 // Test user with full capabilities. 405 if ($role === 'teacher') { 406 $this->setUser($this->teacher); 407 } else { 408 $this->setUser($this->student); 409 } 410 411 // Create the feedback. 412 $data = ['course' => $this->course->id]; 413 if (array_key_exists('closed', $info) && $info['closed']) { 414 $data['timeopen'] = time() + DAYSECS; 415 } 416 $feedback = $this->getDataGenerator()->create_module('feedback', $data); 417 418 $empty = true; 419 if (!array_key_exists('empty', $info) || !$info['empty']) { 420 $empty = false; 421 /** @var \mod_feedback_generator $feedbackgenerator */ 422 $feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback'); 423 // Add,at least, one item to the feedback. 424 $feedbackgenerator->create_item_label($feedback); 425 } 426 427 if (array_key_exists('complete', $info) && !$info['complete']) { 428 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 429 $coursecontext = \context_course::instance($this->course->id); 430 assign_capability('mod/feedback:complete', CAP_PROHIBIT, $studentrole->id, $coursecontext->id); 431 // Empty all the caches that may be affected by this change. 432 accesslib_clear_all_caches_for_unit_testing(); 433 \course_modinfo::clear_instance_cache(); 434 } 435 436 $result = mod_feedback_external::get_items($feedback->id); 437 $result = external_api::clean_returnvalue(mod_feedback_external::get_items_returns(), $result); 438 if ($warning) { 439 $this->assertEmpty($result['items']); 440 $this->assertCount(1, $result['warnings']); 441 $resultwarning = reset($result['warnings']); 442 if ($warning == 'required_capability_exception') { 443 $this->assertStringContainsString('error/nopermission', $resultwarning['message']); 444 } else { 445 $this->assertEquals($warning, $resultwarning['message']); 446 } 447 } else { 448 if ($empty) { 449 $this->assertEmpty($result['items']); 450 } else { 451 $this->assertCount(1, $result['items']); 452 } 453 $this->assertEmpty($result['warnings']); 454 } 455 } 456 457 /** 458 * Data provider for test_get_items_validation() and test_get_page_items_validation(). 459 * 460 * @return array 461 */ 462 public function items_provider(): array { 463 return [ 464 'Valid feedback (as student)' => [ 465 'role' => 'student', 466 'info' => [], 467 'warning' => null, 468 ], 469 'Closed feedback (as student)' => [ 470 'role' => 'student', 471 'info' => ['closed' => true], 472 'warning' => get_string('feedback_is_not_open', 'feedback'), 473 ], 474 'Empty feedback (as student)' => [ 475 'role' => 'student', 476 'info' => ['empty' => true], 477 'warning' => get_string('no_items_available_yet', 'feedback'), 478 ], 479 'Closed feedback (as student)' => [ 480 'role' => 'student', 481 'info' => ['closed' => true], 482 'warning' => get_string('feedback_is_not_open', 'feedback'), 483 ], 484 'Cannot complete feedback (as student)' => [ 485 'role' => 'student', 486 'info' => ['complete' => false], 487 'warning' => 'required_capability_exception', 488 ], 489 'Valid feedback (as teacher)' => [ 490 'role' => 'teacher', 491 'info' => [], 492 'warning' => null, 493 ], 494 'Closed feedback (as teacher)' => [ 495 'role' => 'teacher', 496 'info' => ['closed' => true], 497 'warning' => null, 498 ], 499 'Empty feedback (as teacher)' => [ 500 'role' => 'teacher', 501 'info' => ['empty' => true], 502 'warning' => null, 503 ], 504 'Closed feedback (as teacher)' => [ 505 'role' => 'teacher', 506 'info' => ['closed' => true], 507 'warning' => null, 508 ], 509 'Cannot complete feedback (as teacher)' => [ 510 'role' => 'teacher', 511 'info' => ['complete' => false], 512 'warning' => null, 513 ], 514 ]; 515 } 516 517 /** 518 * Test launch_feedback. 519 */ 520 public function test_launch_feedback() { 521 global $DB; 522 523 // Test user with full capabilities. 524 $this->setUser($this->student); 525 526 // Add questions to the feedback, we are adding 2 pages of questions. 527 $itemscreated = self::populate_feedback($this->feedback, 2); 528 529 // First try a feedback we didn't attempt. 530 $result = mod_feedback_external::launch_feedback($this->feedback->id); 531 $result = external_api::clean_returnvalue(mod_feedback_external::launch_feedback_returns(), $result); 532 $this->assertEquals(0, $result['gopage']); 533 534 // Now, try a feedback that we attempted. 535 // Force non anonymous. 536 $DB->set_field('feedback', 'anonymous', FEEDBACK_ANONYMOUS_NO, array('id' => $this->feedback->id)); 537 // Add a completed_tmp record. 538 $record = [ 539 'feedback' => $this->feedback->id, 540 'userid' => $this->student->id, 541 'guestid' => '', 542 'timemodified' => time() - DAYSECS, 543 'random_response' => 0, 544 'anonymous_response' => FEEDBACK_ANONYMOUS_NO, 545 'courseid' => $this->course->id, 546 ]; 547 $record['id'] = $DB->insert_record('feedback_completedtmp', (object) $record); 548 549 // Add a response to the feedback for each question type with possible values. 550 $response = [ 551 'course_id' => $this->course->id, 552 'item' => $itemscreated[1]->id, // First item is the info question. 553 'completed' => $record['id'], 554 'tmp_completed' => $record['id'], 555 'value' => 'A', 556 ]; 557 $DB->insert_record('feedback_valuetmp', (object) $response); 558 $response = [ 559 'course_id' => $this->course->id, 560 'item' => $itemscreated[2]->id, // Second item is the numeric question. 561 'completed' => $record['id'], 562 'tmp_completed' => $record['id'], 563 'value' => 5, 564 ]; 565 $DB->insert_record('feedback_valuetmp', (object) $response); 566 567 $result = mod_feedback_external::launch_feedback($this->feedback->id); 568 $result = external_api::clean_returnvalue(mod_feedback_external::launch_feedback_returns(), $result); 569 $this->assertEquals(1, $result['gopage']); 570 } 571 572 /** 573 * Test get_page_items. 574 */ 575 public function test_get_page_items() { 576 // Test user with full capabilities. 577 $this->setUser($this->student); 578 579 // Add questions to the feedback, we are adding 2 pages of questions. 580 $itemscreated = self::populate_feedback($this->feedback, 2); 581 582 // Retrieve first page. 583 $result = mod_feedback_external::get_page_items($this->feedback->id, 0); 584 $result = external_api::clean_returnvalue(mod_feedback_external::get_page_items_returns(), $result); 585 $this->assertCount(3, $result['items']); // The first page has 3 items. 586 $this->assertTrue($result['hasnextpage']); 587 $this->assertFalse($result['hasprevpage']); 588 589 // Retrieve second page. 590 $result = mod_feedback_external::get_page_items($this->feedback->id, 1); 591 $result = external_api::clean_returnvalue(mod_feedback_external::get_page_items_returns(), $result); 592 $this->assertCount(5, $result['items']); // The second page has 5 items (page break doesn't count). 593 $this->assertFalse($result['hasnextpage']); 594 $this->assertTrue($result['hasprevpage']); 595 } 596 597 /** 598 * Test get_page_items, to confirm validation is done too. 599 * 600 * @dataProvider items_provider 601 * @param string $role Whether the current user should be a student or a teacher. 602 * @param array $info Settings to create the feedback. 603 * @param string|null $warning The warning message to display or null if warnings result is empty. 604 */ 605 public function test_get_page_items_validation(string $role, array $info, ?string $warning): void { 606 global $DB; 607 608 // Test user with full capabilities. 609 if ($role === 'teacher') { 610 $this->setUser($this->teacher); 611 } else { 612 $this->setUser($this->student); 613 } 614 615 // Create the feedback. 616 $data = ['course' => $this->course->id]; 617 if (array_key_exists('closed', $info) && $info['closed']) { 618 $data['timeopen'] = time() + DAYSECS; 619 } 620 $feedback = $this->getDataGenerator()->create_module('feedback', $data); 621 622 $empty = true; 623 if (!array_key_exists('empty', $info) || !$info['empty']) { 624 $empty = false; 625 /** @var \mod_feedback_generator $feedbackgenerator */ 626 $feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback'); 627 // Add,at least, one item to the feedback. 628 $feedbackgenerator->create_item_label($feedback); 629 } 630 631 if (array_key_exists('complete', $info) && !$info['complete']) { 632 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 633 $coursecontext = \context_course::instance($this->course->id); 634 assign_capability('mod/feedback:complete', CAP_PROHIBIT, $studentrole->id, $coursecontext->id); 635 // Empty all the caches that may be affected by this change. 636 accesslib_clear_all_caches_for_unit_testing(); 637 \course_modinfo::clear_instance_cache(); 638 } 639 640 $result = mod_feedback_external::get_page_items($feedback->id, 0); 641 $result = external_api::clean_returnvalue(mod_feedback_external::get_items_returns(), $result); 642 if ($warning) { 643 $this->assertEmpty($result['items']); 644 $this->assertCount(1, $result['warnings']); 645 $resultwarning = reset($result['warnings']); 646 if ($warning == 'required_capability_exception') { 647 $this->assertStringContainsString('error/nopermission', $resultwarning['message']); 648 } else { 649 $this->assertEquals($warning, $resultwarning['message']); 650 } 651 } else { 652 if ($empty) { 653 $this->assertEmpty($result['items']); 654 } else { 655 $this->assertCount(1, $result['items']); 656 } 657 $this->assertEmpty($result['warnings']); 658 } 659 } 660 661 /** 662 * Test process_page. 663 */ 664 public function test_process_page() { 665 global $DB; 666 667 // Test user with full capabilities. 668 $this->setUser($this->student); 669 $pagecontents = 'You finished it!'; 670 $DB->set_field('feedback', 'page_after_submit', $pagecontents, array('id' => $this->feedback->id)); 671 672 // Add questions to the feedback, we are adding 2 pages of questions. 673 $itemscreated = self::populate_feedback($this->feedback, 2); 674 675 $data = []; 676 foreach ($itemscreated as $item) { 677 678 if (empty($item->hasvalue)) { 679 continue; 680 } 681 682 switch ($item->typ) { 683 case 'textarea': 684 case 'textfield': 685 $value = 'Lorem ipsum'; 686 break; 687 case 'numeric': 688 $value = 5; 689 break; 690 case 'multichoice': 691 $value = '1'; 692 break; 693 case 'multichoicerated': 694 $value = '1'; 695 break; 696 case 'info': 697 $value = format_string($this->course->shortname, true, array('context' => $this->context)); 698 break; 699 default: 700 $value = ''; 701 } 702 $data[] = ['name' => $item->typ . '_' . $item->id, 'value' => $value]; 703 } 704 705 // Process first page. 706 $firstpagedata = [$data[0], $data[1]]; 707 $result = mod_feedback_external::process_page($this->feedback->id, 0, $firstpagedata); 708 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 709 $this->assertEquals(1, $result['jumpto']); 710 $this->assertFalse($result['completed']); 711 712 // Now, process the second page. But first we are going back to the first page. 713 $secondpagedata = [$data[2], $data[3], $data[4], $data[5], $data[6]]; 714 $result = mod_feedback_external::process_page($this->feedback->id, 1, $secondpagedata, true); 715 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 716 $this->assertFalse($result['completed']); 717 $this->assertEquals(0, $result['jumpto']); // We jumped to the first page. 718 // Check the values were correctly saved. 719 $tmpitems = $DB->get_records('feedback_valuetmp'); 720 $this->assertCount(7, $tmpitems); // 2 from the first page + 5 from the second page. 721 722 // Go forward again (sending the same data). 723 $result = mod_feedback_external::process_page($this->feedback->id, 0, $firstpagedata); 724 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 725 $this->assertEquals(1, $result['jumpto']); 726 $this->assertFalse($result['completed']); 727 $tmpitems = $DB->get_records('feedback_valuetmp'); 728 $this->assertCount(7, $tmpitems); // 2 from the first page + 5 from the second page. 729 730 // And finally, save everything! We are going to modify one previous recorded value. 731 $messagessink = $this->redirectMessages(); 732 $data[2]['value'] = 2; // 2 is value of the option 'b'. 733 $secondpagedata = [$data[2], $data[3], $data[4], $data[5], $data[6]]; 734 $result = mod_feedback_external::process_page($this->feedback->id, 1, $secondpagedata); 735 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 736 $this->assertTrue($result['completed']); 737 $this->assertTrue(strpos($result['completionpagecontents'], $pagecontents) !== false); 738 // Check all the items were saved. 739 $items = $DB->get_records('feedback_value'); 740 $this->assertCount(7, $items); 741 // Check if the one we modified was correctly saved. 742 $itemid = $itemscreated[4]->id; 743 $itemsaved = $DB->get_field('feedback_value', 'value', array('item' => $itemid)); 744 $mcitem = new feedback_item_multichoice(); 745 $itemval = $mcitem->get_printval($itemscreated[4], (object) ['value' => $itemsaved]); 746 $this->assertEquals('b', $itemval); 747 748 // Check that the answers are saved for course 0. 749 foreach ($items as $item) { 750 $this->assertEquals(0, $item->course_id); 751 } 752 $completed = $DB->get_record('feedback_completed', []); 753 $this->assertEquals(0, $completed->courseid); 754 755 // Test notifications sent. 756 $messages = $messagessink->get_messages(); 757 $messagessink->close(); 758 // Test customdata. 759 $customdata = json_decode($messages[0]->customdata); 760 $this->assertEquals($this->feedback->id, $customdata->instance); 761 $this->assertEquals($this->feedback->cmid, $customdata->cmid); 762 $this->assertObjectHasAttribute('notificationiconurl', $customdata); 763 } 764 765 /** 766 * Test process_page for a site feedback. 767 */ 768 public function test_process_page_site_feedback() { 769 global $DB; 770 $pagecontents = 'You finished it!'; 771 $this->feedback = $this->getDataGenerator()->create_module('feedback', 772 array('course' => SITEID, 'page_after_submit' => $pagecontents)); 773 774 // Test user with full capabilities. 775 $this->setUser($this->student); 776 777 // Add questions to the feedback, we are adding 2 pages of questions. 778 $itemscreated = self::populate_feedback($this->feedback, 2); 779 780 $data = []; 781 foreach ($itemscreated as $item) { 782 783 if (empty($item->hasvalue)) { 784 continue; 785 } 786 787 switch ($item->typ) { 788 case 'textarea': 789 case 'textfield': 790 $value = 'Lorem ipsum'; 791 break; 792 case 'numeric': 793 $value = 5; 794 break; 795 case 'multichoice': 796 $value = '1'; 797 break; 798 case 'multichoicerated': 799 $value = '1'; 800 break; 801 case 'info': 802 $value = format_string($this->course->shortname, true, array('context' => $this->context)); 803 break; 804 default: 805 $value = ''; 806 } 807 $data[] = ['name' => $item->typ . '_' . $item->id, 'value' => $value]; 808 } 809 810 // Process first page. 811 $firstpagedata = [$data[0], $data[1]]; 812 $result = mod_feedback_external::process_page($this->feedback->id, 0, $firstpagedata, false, $this->course->id); 813 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 814 $this->assertEquals(1, $result['jumpto']); 815 $this->assertFalse($result['completed']); 816 817 // Process second page. 818 $data[2]['value'] = 2; // 2 is value of the option 'b'; 819 $secondpagedata = [$data[2], $data[3], $data[4], $data[5], $data[6]]; 820 $result = mod_feedback_external::process_page($this->feedback->id, 1, $secondpagedata, false, $this->course->id); 821 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 822 $this->assertTrue($result['completed']); 823 $this->assertTrue(strpos($result['completionpagecontents'], $pagecontents) !== false); 824 // Check all the items were saved. 825 $items = $DB->get_records('feedback_value'); 826 $this->assertCount(7, $items); 827 // Check if the one we modified was correctly saved. 828 $itemid = $itemscreated[4]->id; 829 $itemsaved = $DB->get_field('feedback_value', 'value', array('item' => $itemid)); 830 $mcitem = new feedback_item_multichoice(); 831 $itemval = $mcitem->get_printval($itemscreated[4], (object) ['value' => $itemsaved]); 832 $this->assertEquals('b', $itemval); 833 834 // Check that the answers are saved for the correct course. 835 foreach ($items as $item) { 836 $this->assertEquals($this->course->id, $item->course_id); 837 } 838 $completed = $DB->get_record('feedback_completed', []); 839 $this->assertEquals($this->course->id, $completed->courseid); 840 } 841 842 /** 843 * Test get_analysis. 844 */ 845 public function test_get_analysis() { 846 // Test user with full capabilities. 847 $this->setUser($this->student); 848 849 // Create a very simple feedback. 850 $feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback'); 851 $numericitem = $feedbackgenerator->create_item_numeric($this->feedback); 852 $textfielditem = $feedbackgenerator->create_item_textfield($this->feedback); 853 854 $pagedata = [ 855 ['name' => $numericitem->typ .'_'. $numericitem->id, 'value' => 5], 856 ['name' => $textfielditem->typ .'_'. $textfielditem->id, 'value' => 'abc'], 857 ]; 858 // Process the feedback, there is only one page so the feedback will be completed. 859 $result = mod_feedback_external::process_page($this->feedback->id, 0, $pagedata); 860 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 861 $this->assertTrue($result['completed']); 862 863 // Retrieve analysis. 864 $this->setUser($this->teacher); 865 $result = mod_feedback_external::get_analysis($this->feedback->id); 866 $result = external_api::clean_returnvalue(mod_feedback_external::get_analysis_returns(), $result); 867 $this->assertEquals(1, $result['completedcount']); // 1 feedback completed. 868 $this->assertEquals(2, $result['itemscount']); // 2 items in the feedback. 869 $this->assertCount(2, $result['itemsdata']); 870 $this->assertCount(1, $result['itemsdata'][0]['data']); // There are 1 response per item. 871 $this->assertCount(1, $result['itemsdata'][1]['data']); 872 // Check we receive the info the students filled. 873 foreach ($result['itemsdata'] as $data) { 874 if ($data['item']['id'] == $numericitem->id) { 875 $this->assertEquals(5, $data['data'][0]); 876 } else { 877 $this->assertEquals('abc', $data['data'][0]); 878 } 879 } 880 881 // Create another user / response. 882 $anotherstudent = self::getDataGenerator()->create_user(); 883 $this->getDataGenerator()->enrol_user($anotherstudent->id, $this->course->id, $this->studentrole->id, 'manual'); 884 $this->setUser($anotherstudent); 885 886 // Process the feedback, there is only one page so the feedback will be completed. 887 $result = mod_feedback_external::process_page($this->feedback->id, 0, $pagedata); 888 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 889 $this->assertTrue($result['completed']); 890 891 // Retrieve analysis. 892 $this->setUser($this->teacher); 893 $result = mod_feedback_external::get_analysis($this->feedback->id); 894 $result = external_api::clean_returnvalue(mod_feedback_external::get_analysis_returns(), $result); 895 $this->assertEquals(2, $result['completedcount']); // 2 feedback completed. 896 $this->assertEquals(2, $result['itemscount']); 897 $this->assertCount(2, $result['itemsdata'][0]['data']); // There are 2 responses per item. 898 $this->assertCount(2, $result['itemsdata'][1]['data']); 899 } 900 901 /** 902 * Test get_unfinished_responses. 903 */ 904 public function test_get_unfinished_responses() { 905 // Test user with full capabilities. 906 $this->setUser($this->student); 907 908 // Create a very simple feedback. 909 $feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback'); 910 $numericitem = $feedbackgenerator->create_item_numeric($this->feedback); 911 $textfielditem = $feedbackgenerator->create_item_textfield($this->feedback); 912 $feedbackgenerator->create_item_pagebreak($this->feedback); 913 $labelitem = $feedbackgenerator->create_item_label($this->feedback); 914 $numericitem2 = $feedbackgenerator->create_item_numeric($this->feedback); 915 916 $pagedata = [ 917 ['name' => $numericitem->typ .'_'. $numericitem->id, 'value' => 5], 918 ['name' => $textfielditem->typ .'_'. $textfielditem->id, 'value' => 'abc'], 919 ]; 920 // Process the feedback, there are two pages so the feedback will be unfinished yet. 921 $result = mod_feedback_external::process_page($this->feedback->id, 0, $pagedata); 922 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 923 $this->assertFalse($result['completed']); 924 925 // Retrieve the unfinished responses. 926 $result = mod_feedback_external::get_unfinished_responses($this->feedback->id); 927 $result = external_api::clean_returnvalue(mod_feedback_external::get_unfinished_responses_returns(), $result); 928 // Check that ids and responses match. 929 foreach ($result['responses'] as $r) { 930 if ($r['item'] == $numericitem->id) { 931 $this->assertEquals(5, $r['value']); 932 } else { 933 $this->assertEquals($textfielditem->id, $r['item']); 934 $this->assertEquals('abc', $r['value']); 935 } 936 } 937 } 938 939 /** 940 * Test get_finished_responses. 941 */ 942 public function test_get_finished_responses() { 943 // Test user with full capabilities. 944 $this->setUser($this->student); 945 946 // Create a very simple feedback. 947 $feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback'); 948 $numericitem = $feedbackgenerator->create_item_numeric($this->feedback); 949 $textfielditem = $feedbackgenerator->create_item_textfield($this->feedback); 950 951 $pagedata = [ 952 ['name' => $numericitem->typ .'_'. $numericitem->id, 'value' => 5], 953 ['name' => $textfielditem->typ .'_'. $textfielditem->id, 'value' => 'abc'], 954 ]; 955 956 // Process the feedback, there is only one page so the feedback will be completed. 957 $result = mod_feedback_external::process_page($this->feedback->id, 0, $pagedata); 958 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 959 $this->assertTrue($result['completed']); 960 961 // Retrieve the responses. 962 $result = mod_feedback_external::get_finished_responses($this->feedback->id); 963 $result = external_api::clean_returnvalue(mod_feedback_external::get_finished_responses_returns(), $result); 964 // Check that ids and responses match. 965 foreach ($result['responses'] as $r) { 966 if ($r['item'] == $numericitem->id) { 967 $this->assertEquals(5, $r['value']); 968 } else { 969 $this->assertEquals($textfielditem->id, $r['item']); 970 $this->assertEquals('abc', $r['value']); 971 } 972 } 973 } 974 975 /** 976 * Test get_non_respondents (student trying to get this information). 977 */ 978 public function test_get_non_respondents_no_permissions() { 979 $this->setUser($this->student); 980 $this->expectException(moodle_exception::class); 981 mod_feedback_external::get_non_respondents($this->feedback->id); 982 } 983 984 /** 985 * Test get_non_respondents from an anonymous feedback. 986 */ 987 public function test_get_non_respondents_from_anonymous_feedback() { 988 $this->setUser($this->student); 989 $this->expectException(moodle_exception::class); 990 $this->expectExceptionMessage(get_string('anonymous', 'feedback')); 991 mod_feedback_external::get_non_respondents($this->feedback->id); 992 } 993 994 /** 995 * Test get_non_respondents. 996 */ 997 public function test_get_non_respondents() { 998 global $DB; 999 1000 // Force non anonymous. 1001 $DB->set_field('feedback', 'anonymous', FEEDBACK_ANONYMOUS_NO, array('id' => $this->feedback->id)); 1002 1003 // Create another student. 1004 $anotherstudent = self::getDataGenerator()->create_user(); 1005 $this->getDataGenerator()->enrol_user($anotherstudent->id, $this->course->id, $this->studentrole->id, 'manual'); 1006 $this->setUser($anotherstudent); 1007 1008 // Test user with full capabilities. 1009 $this->setUser($this->student); 1010 1011 // Create a very simple feedback. 1012 $feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback'); 1013 $numericitem = $feedbackgenerator->create_item_numeric($this->feedback); 1014 1015 $pagedata = [ 1016 ['name' => $numericitem->typ .'_'. $numericitem->id, 'value' => 5], 1017 ]; 1018 1019 // Process the feedback, there is only one page so the feedback will be completed. 1020 $result = mod_feedback_external::process_page($this->feedback->id, 0, $pagedata); 1021 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 1022 $this->assertTrue($result['completed']); 1023 1024 // Retrieve the non-respondent users. 1025 $this->setUser($this->teacher); 1026 $result = mod_feedback_external::get_non_respondents($this->feedback->id); 1027 $result = external_api::clean_returnvalue(mod_feedback_external::get_non_respondents_returns(), $result); 1028 $this->assertCount(0, $result['warnings']); 1029 $this->assertCount(1, $result['users']); 1030 $this->assertEquals($anotherstudent->id, $result['users'][0]['userid']); 1031 1032 // Create another student. 1033 $anotherstudent2 = self::getDataGenerator()->create_user(); 1034 $this->getDataGenerator()->enrol_user($anotherstudent2->id, $this->course->id, $this->studentrole->id, 'manual'); 1035 $this->setUser($anotherstudent2); 1036 $this->setUser($this->teacher); 1037 $result = mod_feedback_external::get_non_respondents($this->feedback->id); 1038 $result = external_api::clean_returnvalue(mod_feedback_external::get_non_respondents_returns(), $result); 1039 $this->assertCount(0, $result['warnings']); 1040 $this->assertCount(2, $result['users']); 1041 1042 // Test pagination. 1043 $result = mod_feedback_external::get_non_respondents($this->feedback->id, 0, 'lastaccess', 0, 1); 1044 $result = external_api::clean_returnvalue(mod_feedback_external::get_non_respondents_returns(), $result); 1045 $this->assertCount(0, $result['warnings']); 1046 $this->assertCount(1, $result['users']); 1047 } 1048 1049 /** 1050 * Helper function that completes the feedback for two students. 1051 */ 1052 protected function complete_basic_feedback() { 1053 global $DB; 1054 1055 $generator = $this->getDataGenerator(); 1056 // Create separated groups. 1057 $DB->set_field('course', 'groupmode', SEPARATEGROUPS); 1058 $DB->set_field('course', 'groupmodeforce', 1); 1059 assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $this->teacherrole->id, $this->context); 1060 accesslib_clear_all_caches_for_unit_testing(); 1061 1062 $group1 = $generator->create_group(array('courseid' => $this->course->id)); 1063 $group2 = $generator->create_group(array('courseid' => $this->course->id)); 1064 1065 // Create another students. 1066 $anotherstudent1 = self::getDataGenerator()->create_user(); 1067 $anotherstudent2 = self::getDataGenerator()->create_user(); 1068 $generator->enrol_user($anotherstudent1->id, $this->course->id, $this->studentrole->id, 'manual'); 1069 $generator->enrol_user($anotherstudent2->id, $this->course->id, $this->studentrole->id, 'manual'); 1070 1071 $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $this->student->id)); 1072 $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $this->teacher->id)); 1073 $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $anotherstudent1->id)); 1074 $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $anotherstudent2->id)); 1075 1076 // Test user with full capabilities. 1077 $this->setUser($this->student); 1078 1079 // Create a very simple feedback. 1080 $feedbackgenerator = $generator->get_plugin_generator('mod_feedback'); 1081 $numericitem = $feedbackgenerator->create_item_numeric($this->feedback); 1082 $textfielditem = $feedbackgenerator->create_item_textfield($this->feedback); 1083 1084 $pagedata = [ 1085 ['name' => $numericitem->typ .'_'. $numericitem->id, 'value' => 5], 1086 ['name' => $textfielditem->typ .'_'. $textfielditem->id, 'value' => 'abc'], 1087 ]; 1088 1089 // Process the feedback, there is only one page so the feedback will be completed. 1090 $result = mod_feedback_external::process_page($this->feedback->id, 0, $pagedata); 1091 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 1092 $this->assertTrue($result['completed']); 1093 1094 $this->setUser($anotherstudent1); 1095 1096 $pagedata = [ 1097 ['name' => $numericitem->typ .'_'. $numericitem->id, 'value' => 10], 1098 ['name' => $textfielditem->typ .'_'. $textfielditem->id, 'value' => 'def'], 1099 ]; 1100 1101 $result = mod_feedback_external::process_page($this->feedback->id, 0, $pagedata); 1102 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 1103 $this->assertTrue($result['completed']); 1104 1105 $this->setUser($anotherstudent2); 1106 1107 $pagedata = [ 1108 ['name' => $numericitem->typ .'_'. $numericitem->id, 'value' => 10], 1109 ['name' => $textfielditem->typ .'_'. $textfielditem->id, 'value' => 'def'], 1110 ]; 1111 1112 $result = mod_feedback_external::process_page($this->feedback->id, 0, $pagedata); 1113 $result = external_api::clean_returnvalue(mod_feedback_external::process_page_returns(), $result); 1114 $this->assertTrue($result['completed']); 1115 } 1116 1117 /** 1118 * Test get_responses_analysis for anonymous feedback. 1119 */ 1120 public function test_get_responses_analysis_anonymous() { 1121 self::complete_basic_feedback(); 1122 1123 // Retrieve the responses analysis. 1124 $this->setUser($this->teacher); 1125 $result = mod_feedback_external::get_responses_analysis($this->feedback->id); 1126 $result = external_api::clean_returnvalue(mod_feedback_external::get_responses_analysis_returns(), $result); 1127 $this->assertCount(0, $result['warnings']); 1128 $this->assertEquals(0, $result['totalattempts']); 1129 $this->assertEquals(2, $result['totalanonattempts']); // Only see my groups. 1130 1131 foreach ($result['attempts'] as $attempt) { 1132 $this->assertEmpty($attempt['userid']); // Is anonymous. 1133 } 1134 } 1135 1136 /** 1137 * Test get_responses_analysis for non-anonymous feedback. 1138 */ 1139 public function test_get_responses_analysis_non_anonymous() { 1140 global $DB; 1141 1142 // Force non anonymous. 1143 $DB->set_field('feedback', 'anonymous', FEEDBACK_ANONYMOUS_NO, array('id' => $this->feedback->id)); 1144 1145 self::complete_basic_feedback(); 1146 // Retrieve the responses analysis. 1147 $this->setUser($this->teacher); 1148 $result = mod_feedback_external::get_responses_analysis($this->feedback->id); 1149 $result = external_api::clean_returnvalue(mod_feedback_external::get_responses_analysis_returns(), $result); 1150 $this->assertCount(0, $result['warnings']); 1151 $this->assertEquals(2, $result['totalattempts']); 1152 $this->assertEquals(0, $result['totalanonattempts']); // Only see my groups. 1153 1154 foreach ($result['attempts'] as $attempt) { 1155 $this->assertNotEmpty($attempt['userid']); // Is not anonymous. 1156 } 1157 } 1158 1159 /** 1160 * Test get_last_completed for feedback anonymous not completed. 1161 */ 1162 public function test_get_last_completed_anonymous_not_completed() { 1163 global $DB; 1164 1165 // Force anonymous. 1166 $DB->set_field('feedback', 'anonymous', FEEDBACK_ANONYMOUS_YES, array('id' => $this->feedback->id)); 1167 1168 // Test user with full capabilities that didn't complete the feedback. 1169 $this->setUser($this->student); 1170 1171 $this->expectExceptionMessage(get_string('anonymous', 'feedback')); 1172 $this->expectException(moodle_exception::class); 1173 mod_feedback_external::get_last_completed($this->feedback->id); 1174 } 1175 1176 /** 1177 * Test get_last_completed for feedback anonymous and completed. 1178 */ 1179 public function test_get_last_completed_anonymous_completed() { 1180 global $DB; 1181 1182 // Force anonymous. 1183 $DB->set_field('feedback', 'anonymous', FEEDBACK_ANONYMOUS_YES, array('id' => $this->feedback->id)); 1184 // Add one completion record.. 1185 $record = [ 1186 'feedback' => $this->feedback->id, 1187 'userid' => $this->student->id, 1188 'timemodified' => time() - DAYSECS, 1189 'random_response' => 0, 1190 'anonymous_response' => FEEDBACK_ANONYMOUS_YES, 1191 'courseid' => $this->course->id, 1192 ]; 1193 $record['id'] = $DB->insert_record('feedback_completed', (object) $record); 1194 1195 // Test user with full capabilities. 1196 $this->setUser($this->student); 1197 1198 $this->expectExceptionMessage(get_string('anonymous', 'feedback')); 1199 $this->expectException(moodle_exception::class); 1200 mod_feedback_external::get_last_completed($this->feedback->id); 1201 } 1202 1203 /** 1204 * Test get_last_completed for feedback not anonymous and completed. 1205 */ 1206 public function test_get_last_completed_not_anonymous_completed() { 1207 global $DB; 1208 1209 // Force non anonymous. 1210 $DB->set_field('feedback', 'anonymous', FEEDBACK_ANONYMOUS_NO, array('id' => $this->feedback->id)); 1211 // Add one completion record.. 1212 $record = [ 1213 'feedback' => $this->feedback->id, 1214 'userid' => $this->student->id, 1215 'timemodified' => time() - DAYSECS, 1216 'random_response' => 0, 1217 'anonymous_response' => FEEDBACK_ANONYMOUS_NO, 1218 'courseid' => $this->course->id, 1219 ]; 1220 $record['id'] = $DB->insert_record('feedback_completed', (object) $record); 1221 1222 // Test user with full capabilities. 1223 $this->setUser($this->student); 1224 $result = mod_feedback_external::get_last_completed($this->feedback->id); 1225 $result = external_api::clean_returnvalue(mod_feedback_external::get_last_completed_returns(), $result); 1226 $this->assertEquals($record, $result['completed']); 1227 } 1228 1229 /** 1230 * Test get_last_completed for feedback not anonymous and not completed. 1231 */ 1232 public function test_get_last_completed_not_anonymous_not_completed() { 1233 global $DB; 1234 1235 // Force anonymous. 1236 $DB->set_field('feedback', 'anonymous', FEEDBACK_ANONYMOUS_NO, array('id' => $this->feedback->id)); 1237 1238 // Test user with full capabilities that didn't complete the feedback. 1239 $this->setUser($this->student); 1240 1241 $this->expectExceptionMessage(get_string('not_completed_yet', 'feedback')); 1242 $this->expectException(moodle_exception::class); 1243 mod_feedback_external::get_last_completed($this->feedback->id); 1244 } 1245 1246 /** 1247 * Test get_feedback_access_information for site feedback. 1248 */ 1249 public function test_get_feedback_access_information_for_site_feedback() { 1250 1251 $sitefeedback = $this->getDataGenerator()->create_module('feedback', array('course' => SITEID)); 1252 $this->setUser($this->student); 1253 // Access the site feedback via the site activity. 1254 $result = mod_feedback_external::get_feedback_access_information($sitefeedback->id); 1255 $result = external_api::clean_returnvalue(mod_feedback_external::get_feedback_access_information_returns(), $result); 1256 $this->assertTrue($result['cancomplete']); 1257 $this->assertTrue($result['cansubmit']); 1258 1259 // Access the site feedback via course where I'm enrolled. 1260 $result = mod_feedback_external::get_feedback_access_information($sitefeedback->id, $this->course->id); 1261 $result = external_api::clean_returnvalue(mod_feedback_external::get_feedback_access_information_returns(), $result); 1262 $this->assertTrue($result['cancomplete']); 1263 $this->assertTrue($result['cansubmit']); 1264 1265 // Access the site feedback via course where I'm not enrolled. 1266 $othercourse = $this->getDataGenerator()->create_course(); 1267 1268 $this->expectException(moodle_exception::class); 1269 mod_feedback_external::get_feedback_access_information($sitefeedback->id, $othercourse->id); 1270 } 1271 1272 /** 1273 * Test get_feedback_access_information for site feedback mapped. 1274 */ 1275 public function test_get_feedback_access_information_for_site_feedback_mapped() { 1276 global $DB; 1277 1278 $sitefeedback = $this->getDataGenerator()->create_module('feedback', array('course' => SITEID)); 1279 $this->setUser($this->student); 1280 $DB->insert_record('feedback_sitecourse_map', array('feedbackid' => $sitefeedback->id, 'courseid' => $this->course->id)); 1281 1282 // Access the site feedback via course where I'm enrolled and mapped. 1283 $result = mod_feedback_external::get_feedback_access_information($sitefeedback->id, $this->course->id); 1284 $result = external_api::clean_returnvalue(mod_feedback_external::get_feedback_access_information_returns(), $result); 1285 $this->assertTrue($result['cancomplete']); 1286 $this->assertTrue($result['cansubmit']); 1287 1288 // Access the site feedback via course where I'm enrolled but not mapped. 1289 $othercourse = $this->getDataGenerator()->create_course(); 1290 $this->getDataGenerator()->enrol_user($this->student->id, $othercourse->id, $this->studentrole->id, 'manual'); 1291 1292 $this->expectException(moodle_exception::class); 1293 $this->expectExceptionMessage(get_string('cannotaccess', 'mod_feedback')); 1294 mod_feedback_external::get_feedback_access_information($sitefeedback->id, $othercourse->id); 1295 } 1296 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body