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 defined('MOODLE_INTERNAL') || die(); 18 19 global $CFG; 20 21 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 22 require_once($CFG->dirroot . '/mod/assign/externallib.php'); 23 require_once (__DIR__ . '/fixtures/testable_assign.php'); 24 25 /** 26 * External mod assign functions unit tests 27 * 28 * @package mod_assign 29 * @category external 30 * @copyright 2012 Paul Charsley 31 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 */ 33 class mod_assign_external_testcase extends externallib_advanced_testcase { 34 35 /** 36 * Test get_grades 37 */ 38 public function test_get_grades() { 39 global $DB, $USER; 40 41 $this->resetAfterTest(true); 42 // Create a course and assignment. 43 $coursedata['idnumber'] = 'idnumbercourse'; 44 $coursedata['fullname'] = 'Lightwork Course'; 45 $coursedata['summary'] = 'Lightwork Course description'; 46 $coursedata['summaryformat'] = FORMAT_MOODLE; 47 $course = self::getDataGenerator()->create_course($coursedata); 48 49 $assigndata['course'] = $course->id; 50 $assigndata['name'] = 'lightwork assignment'; 51 52 $assign = self::getDataGenerator()->create_module('assign', $assigndata); 53 54 // Create a manual enrolment record. 55 $manualenroldata['enrol'] = 'manual'; 56 $manualenroldata['status'] = 0; 57 $manualenroldata['courseid'] = $course->id; 58 $enrolid = $DB->insert_record('enrol', $manualenroldata); 59 60 // Create a teacher and give them capabilities. 61 $context = context_course::instance($course->id); 62 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3); 63 $context = context_module::instance($assign->cmid); 64 $this->assignUserCapability('mod/assign:viewgrades', $context->id, $roleid); 65 66 // Create the teacher's enrolment record. 67 $userenrolmentdata['status'] = 0; 68 $userenrolmentdata['enrolid'] = $enrolid; 69 $userenrolmentdata['userid'] = $USER->id; 70 $DB->insert_record('user_enrolments', $userenrolmentdata); 71 72 // Create a student and give them 2 grades (for 2 attempts). 73 $student = self::getDataGenerator()->create_user(); 74 75 $submission = new stdClass(); 76 $submission->assignment = $assign->id; 77 $submission->userid = $student->id; 78 $submission->status = ASSIGN_SUBMISSION_STATUS_NEW; 79 $submission->latest = 0; 80 $submission->attemptnumber = 0; 81 $submission->groupid = 0; 82 $submission->timecreated = time(); 83 $submission->timemodified = time(); 84 $DB->insert_record('assign_submission', $submission); 85 86 $grade = new stdClass(); 87 $grade->assignment = $assign->id; 88 $grade->userid = $student->id; 89 $grade->timecreated = time(); 90 $grade->timemodified = $grade->timecreated; 91 $grade->grader = $USER->id; 92 $grade->grade = 50; 93 $grade->attemptnumber = 0; 94 $DB->insert_record('assign_grades', $grade); 95 96 $submission = new stdClass(); 97 $submission->assignment = $assign->id; 98 $submission->userid = $student->id; 99 $submission->status = ASSIGN_SUBMISSION_STATUS_NEW; 100 $submission->latest = 1; 101 $submission->attemptnumber = 1; 102 $submission->groupid = 0; 103 $submission->timecreated = time(); 104 $submission->timemodified = time(); 105 $DB->insert_record('assign_submission', $submission); 106 107 $grade = new stdClass(); 108 $grade->assignment = $assign->id; 109 $grade->userid = $student->id; 110 $grade->timecreated = time(); 111 $grade->timemodified = $grade->timecreated; 112 $grade->grader = $USER->id; 113 $grade->grade = 75; 114 $grade->attemptnumber = 1; 115 $DB->insert_record('assign_grades', $grade); 116 117 $assignmentids[] = $assign->id; 118 $result = mod_assign_external::get_grades($assignmentids); 119 120 // We need to execute the return values cleaning process to simulate the web service server. 121 $result = external_api::clean_returnvalue(mod_assign_external::get_grades_returns(), $result); 122 123 // Check that the correct grade information for the student is returned. 124 $this->assertEquals(1, count($result['assignments'])); 125 $assignment = $result['assignments'][0]; 126 $this->assertEquals($assign->id, $assignment['assignmentid']); 127 // Should only get the last grade for this student. 128 $this->assertEquals(1, count($assignment['grades'])); 129 $grade = $assignment['grades'][0]; 130 $this->assertEquals($student->id, $grade['userid']); 131 // Should be the last grade (not the first). 132 $this->assertEquals(75, $grade['grade']); 133 } 134 135 /** 136 * Test get_assignments 137 */ 138 public function test_get_assignments() { 139 global $DB, $USER, $CFG; 140 141 $this->resetAfterTest(true); 142 143 // Enable multilang filter to on content and heading. 144 filter_set_global_state('multilang', TEXTFILTER_ON); 145 filter_set_applies_to_strings('multilang', 1); 146 // Set WS filtering. 147 $wssettings = external_settings::get_instance(); 148 $wssettings->set_filter(true); 149 150 $category = self::getDataGenerator()->create_category(array( 151 'name' => 'Test category' 152 )); 153 154 // Create a course. 155 $course1 = self::getDataGenerator()->create_course(array( 156 'idnumber' => 'idnumbercourse1', 157 'fullname' => '<b>Lightwork Course 1</b>', // Adding tags here to check that external_format_string works. 158 'shortname' => '<b>Lightwork Course 1</b>', // Adding tags here to check that external_format_string works. 159 'summary' => 'Lightwork Course 1 description', 160 'summaryformat' => FORMAT_MOODLE, 161 'category' => $category->id 162 )); 163 164 // Create a second course, just for testing. 165 $course2 = self::getDataGenerator()->create_course(array( 166 'idnumber' => 'idnumbercourse2', 167 'fullname' => 'Lightwork Course 2', 168 'summary' => 'Lightwork Course 2 description', 169 'summaryformat' => FORMAT_MOODLE, 170 'category' => $category->id 171 )); 172 173 // Create the assignment module with links to a filerecord. 174 $assign1 = self::getDataGenerator()->create_module('assign', array( 175 'course' => $course1->id, 176 'name' => '<span lang="en" class="multilang">English</span><span lang="es" class="multilang">EspaƱol</span>', 177 'intro' => 'the assignment intro text here <a href="@@PLUGINFILE@@/intro.txt">link</a>', 178 'introformat' => FORMAT_HTML, 179 'markingworkflow' => 1, 180 'markingallocation' => 1 181 )); 182 183 // Add a file as assignment attachment. 184 $context = context_module::instance($assign1->cmid); 185 $filerecord = array('component' => 'mod_assign', 'filearea' => 'intro', 'contextid' => $context->id, 'itemid' => 0, 186 'filename' => 'intro.txt', 'filepath' => '/'); 187 $fs = get_file_storage(); 188 $fs->create_file_from_string($filerecord, 'Test intro file'); 189 190 // Create manual enrolment record. 191 $enrolid = $DB->insert_record('enrol', (object)array( 192 'enrol' => 'manual', 193 'status' => 0, 194 'courseid' => $course1->id 195 )); 196 197 // Create the user and give them capabilities. 198 $context = context_course::instance($course1->id); 199 $roleid = $this->assignUserCapability('moodle/course:view', $context->id); 200 $context = context_module::instance($assign1->cmid); 201 $this->assignUserCapability('mod/assign:view', $context->id, $roleid); 202 203 // Create the user enrolment record. 204 $DB->insert_record('user_enrolments', (object)array( 205 'status' => 0, 206 'enrolid' => $enrolid, 207 'userid' => $USER->id 208 )); 209 210 // Add a file as assignment attachment. 211 $filerecord = array('component' => 'mod_assign', 'filearea' => ASSIGN_INTROATTACHMENT_FILEAREA, 212 'contextid' => $context->id, 'itemid' => 0, 213 'filename' => 'introattachment.txt', 'filepath' => '/'); 214 $fs = get_file_storage(); 215 $fs->create_file_from_string($filerecord, 'Test intro attachment file'); 216 217 $result = mod_assign_external::get_assignments(); 218 219 // We need to execute the return values cleaning process to simulate the web service server. 220 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result); 221 222 // Check the course and assignment are returned. 223 $this->assertEquals(1, count($result['courses'])); 224 $course = $result['courses'][0]; 225 $this->assertEquals('Lightwork Course 1', $course['fullname']); 226 $this->assertEquals('Lightwork Course 1', $course['shortname']); 227 $this->assertEquals(1, count($course['assignments'])); 228 $assignment = $course['assignments'][0]; 229 $this->assertEquals($assign1->id, $assignment['id']); 230 $this->assertEquals($course1->id, $assignment['course']); 231 $this->assertEquals('English', $assignment['name']); 232 $this->assertContains('the assignment intro text here', $assignment['intro']); 233 $this->assertNotEmpty($assignment['configs']); 234 // Check the url of the file attatched. 235 $this->assertRegExp('@"' . $CFG->wwwroot . '/webservice/pluginfile.php/\d+/mod_assign/intro/intro\.txt"@', $assignment['intro']); 236 $this->assertEquals(1, $assignment['markingworkflow']); 237 $this->assertEquals(1, $assignment['markingallocation']); 238 $this->assertEquals(0, $assignment['preventsubmissionnotingroup']); 239 240 $this->assertCount(1, $assignment['introattachments']); 241 $this->assertEquals('introattachment.txt', $assignment['introattachments'][0]['filename']); 242 243 // Now, hide the descritption until the submission from date. 244 $DB->set_field('assign', 'alwaysshowdescription', 0, array('id' => $assign1->id)); 245 $DB->set_field('assign', 'allowsubmissionsfromdate', time() + DAYSECS, array('id' => $assign1->id)); 246 247 $result = mod_assign_external::get_assignments(array($course1->id)); 248 249 // We need to execute the return values cleaning process to simulate the web service server. 250 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result); 251 252 $this->assertEquals(1, count($result['courses'])); 253 $course = $result['courses'][0]; 254 $this->assertEquals('Lightwork Course 1', $course['fullname']); 255 $this->assertEquals(1, count($course['assignments'])); 256 $assignment = $course['assignments'][0]; 257 $this->assertEquals($assign1->id, $assignment['id']); 258 $this->assertEquals($course1->id, $assignment['course']); 259 $this->assertEquals('English', $assignment['name']); 260 $this->assertArrayNotHasKey('intro', $assignment); 261 $this->assertArrayNotHasKey('introattachments', $assignment); 262 $this->assertEquals(1, $assignment['markingworkflow']); 263 $this->assertEquals(1, $assignment['markingallocation']); 264 $this->assertEquals(0, $assignment['preventsubmissionnotingroup']); 265 266 $result = mod_assign_external::get_assignments(array($course2->id)); 267 268 // We need to execute the return values cleaning process to simulate the web service server. 269 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result); 270 271 $this->assertEquals(0, count($result['courses'])); 272 $this->assertEquals(1, count($result['warnings'])); 273 274 // Test with non-enrolled user, but with view capabilities. 275 $this->setAdminUser(); 276 $result = mod_assign_external::get_assignments(); 277 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result); 278 $this->assertEquals(0, count($result['courses'])); 279 $this->assertEquals(0, count($result['warnings'])); 280 281 // Expect no courses, because we are not using the special flag. 282 $result = mod_assign_external::get_assignments(array($course1->id)); 283 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result); 284 $this->assertCount(0, $result['courses']); 285 286 // Now use the special flag to return courses where you are not enroled in. 287 $result = mod_assign_external::get_assignments(array($course1->id), array(), true); 288 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result); 289 $this->assertCount(1, $result['courses']); 290 291 $course = $result['courses'][0]; 292 $this->assertEquals('Lightwork Course 1', $course['fullname']); 293 $this->assertEquals(1, count($course['assignments'])); 294 $assignment = $course['assignments'][0]; 295 $this->assertEquals($assign1->id, $assignment['id']); 296 $this->assertEquals($course1->id, $assignment['course']); 297 $this->assertEquals('English', $assignment['name']); 298 $this->assertArrayNotHasKey('intro', $assignment); 299 $this->assertArrayNotHasKey('introattachments', $assignment); 300 $this->assertEquals(1, $assignment['markingworkflow']); 301 $this->assertEquals(1, $assignment['markingallocation']); 302 $this->assertEquals(0, $assignment['preventsubmissionnotingroup']); 303 } 304 305 /** 306 * Test get_assignments with submissionstatement. 307 */ 308 public function test_get_assignments_with_submissionstatement() { 309 global $DB, $USER, $CFG; 310 311 $this->resetAfterTest(true); 312 313 // Setup test data. Create 2 assigns, one with requiresubmissionstatement and the other without it. 314 $course = $this->getDataGenerator()->create_course(); 315 $assign = $this->getDataGenerator()->create_module('assign', array( 316 'course' => $course->id, 317 'requiresubmissionstatement' => 1 318 )); 319 $assign2 = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 320 321 // Create student. 322 $student = self::getDataGenerator()->create_user(); 323 324 // Users enrolments. 325 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 326 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); 327 328 // Update the submissionstatement. 329 $submissionstatement = 'This is a fake submission statement.'; 330 set_config('submissionstatement', $submissionstatement, 'assign'); 331 332 $this->setUser($student); 333 334 $result = mod_assign_external::get_assignments(); 335 // We need to execute the return values cleaning process to simulate the web service server. 336 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result); 337 338 // Check that the amount of courses and assignments is right. 339 $this->assertCount(1, $result['courses']); 340 $assignmentsret = $result['courses'][0]['assignments']; 341 $this->assertCount(2, $assignmentsret); 342 343 // Order the returned assignments by ID. 344 usort($assignmentsret, function($a, $b) { 345 return strcmp($a['id'], $b['id']); 346 }); 347 348 // Check that the first assign contains the submission statement. 349 $assignmentret = $assignmentsret[0]; 350 $this->assertEquals($assign->id, $assignmentret['id']); 351 $this->assertEquals(1, $assignmentret['requiresubmissionstatement']); 352 $this->assertEquals($submissionstatement, $assignmentret['submissionstatement']); 353 354 // Check that the second assign does NOT contain the submission statement. 355 $assignmentret = $assignmentsret[1]; 356 $this->assertEquals($assign2->id, $assignmentret['id']); 357 $this->assertEquals(0, $assignmentret['requiresubmissionstatement']); 358 $this->assertArrayNotHasKey('submissionstatement', $assignmentret); 359 } 360 361 /** 362 * Test get_submissions 363 */ 364 public function test_get_submissions() { 365 global $DB, $USER; 366 367 $this->resetAfterTest(true); 368 // Create a course and assignment. 369 $coursedata['idnumber'] = 'idnumbercourse1'; 370 $coursedata['fullname'] = 'Lightwork Course 1'; 371 $coursedata['summary'] = 'Lightwork Course 1 description'; 372 $coursedata['summaryformat'] = FORMAT_MOODLE; 373 $course1 = self::getDataGenerator()->create_course($coursedata); 374 375 $assigndata['course'] = $course1->id; 376 $assigndata['name'] = 'lightwork assignment'; 377 378 $assign1 = self::getDataGenerator()->create_module('assign', $assigndata); 379 380 // Create a student with an online text submission. 381 // First attempt. 382 $student = self::getDataGenerator()->create_user(); 383 $teacher = self::getDataGenerator()->create_user(); 384 $submission = new stdClass(); 385 $submission->assignment = $assign1->id; 386 $submission->userid = $student->id; 387 $submission->timecreated = time(); 388 $submission->timemodified = $submission->timecreated; 389 $submission->status = 'draft'; 390 $submission->attemptnumber = 0; 391 $submission->latest = 0; 392 $sid = $DB->insert_record('assign_submission', $submission); 393 394 // Second attempt. 395 $submission = new stdClass(); 396 $submission->assignment = $assign1->id; 397 $submission->userid = $student->id; 398 $submission->timecreated = time(); 399 $submission->timemodified = $submission->timecreated; 400 $submission->status = 'submitted'; 401 $submission->attemptnumber = 1; 402 $submission->latest = 1; 403 $sid = $DB->insert_record('assign_submission', $submission); 404 $submission->id = $sid; 405 406 $onlinetextsubmission = new stdClass(); 407 $onlinetextsubmission->onlinetext = "<p>online test text</p>"; 408 $onlinetextsubmission->onlineformat = 1; 409 $onlinetextsubmission->submission = $submission->id; 410 $onlinetextsubmission->assignment = $assign1->id; 411 $DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission); 412 413 // Enrol the teacher in the course. 414 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 415 $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id); 416 $this->setUser($teacher); 417 418 $assignmentids[] = $assign1->id; 419 $result = mod_assign_external::get_submissions($assignmentids); 420 $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result); 421 422 // Check the online text submission is NOT returned because the student is not yet enrolled in the course. 423 $this->assertEquals(1, count($result['assignments'])); 424 $assignment = $result['assignments'][0]; 425 $this->assertEquals($assign1->id, $assignment['assignmentid']); 426 $this->assertEquals(0, count($assignment['submissions'])); 427 428 // Enrol the student in the course. 429 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 430 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id); 431 432 $result = mod_assign_external::get_submissions($assignmentids); 433 $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result); 434 435 $this->assertEquals(1, count($result['assignments'])); 436 $assignment = $result['assignments'][0]; 437 $this->assertEquals($assign1->id, $assignment['assignmentid']); 438 // Now, we get the submission because the user is enrolled. 439 $this->assertEquals(1, count($assignment['submissions'])); 440 $submission = $assignment['submissions'][0]; 441 $this->assertEquals($sid, $submission['id']); 442 $this->assertCount(1, $submission['plugins']); 443 $this->assertEquals('notgraded', $submission['gradingstatus']); 444 445 // Test locking the context. 446 set_config('contextlocking', 1); 447 $context = context_course::instance($course1->id); 448 $context->set_locked(true); 449 450 $this->setUser($teacher); 451 $assignmentids[] = $assign1->id; 452 $result = mod_assign_external::get_submissions($assignmentids); 453 $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result); 454 $this->assertEquals(1, count($result['assignments'])); 455 } 456 457 /** 458 * Test get_submissions with teamsubmission enabled 459 */ 460 public function test_get_submissions_group_submission() { 461 global $DB; 462 463 $this->resetAfterTest(true); 464 465 $result = $this->create_assign_with_student_and_teacher(array( 466 'assignsubmission_onlinetext_enabled' => 1, 467 'teamsubmission' => 1 468 )); 469 $assignmodule = $result['assign']; 470 $student = $result['student']; 471 $teacher = $result['teacher']; 472 $course = $result['course']; 473 $context = context_course::instance($course->id); 474 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 475 $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 476 $cm = get_coursemodule_from_instance('assign', $assignmodule->id); 477 $context = context_module::instance($cm->id); 478 $assign = new mod_assign_testable_assign($context, $cm, $course); 479 480 groups_add_member($group, $student); 481 482 $this->setUser($student); 483 $submission = $assign->get_group_submission($student->id, $group->id, true); 484 $sid = $submission->id; 485 486 $this->setUser($teacher); 487 488 $assignmentids[] = $assignmodule->id; 489 $result = mod_assign_external::get_submissions($assignmentids); 490 $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result); 491 492 $this->assertEquals(1, count($result['assignments'])); 493 $assignment = $result['assignments'][0]; 494 $this->assertEquals($assignmodule->id, $assignment['assignmentid']); 495 $this->assertEquals(1, count($assignment['submissions'])); 496 $submission = $assignment['submissions'][0]; 497 $this->assertEquals($sid, $submission['id']); 498 $this->assertEquals($group->id, $submission['groupid']); 499 $this->assertEquals(0, $submission['userid']); 500 } 501 502 /** 503 * Test get_submissions with teamsubmission enabled 504 * and a group having a higher attemptnumber than another 505 */ 506 public function test_get_submissions_group_submission_attemptnumber() { 507 global $DB; 508 $this->resetAfterTest(true); 509 510 $result = $this->create_assign_with_student_and_teacher([ 511 'assignsubmission_onlinetext_enabled' => 1, 512 'attemptreopenmethod' => 'manual', 513 'teamsubmission' => 1, 514 ]); 515 $assignmodule = $result['assign']; 516 $course = $result['course']; 517 518 $teacher = $result['teacher']; 519 $student1 = $result['student']; 520 $student2 = self::getDataGenerator()->create_user(); 521 522 // Enrol second user into the course. 523 $studentrole = $DB->get_record('role', ['shortname' => 'student']); 524 $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id); 525 526 $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 527 groups_add_member($group1, $student1); 528 $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 529 groups_add_member($group2, $student2); 530 531 $this->setUser($student1); 532 mod_assign_external::save_submission( 533 $assignmodule->id, 534 [ 535 'onlinetext_editor' => [ 536 'text' => 'Group 1, Submission 1', 537 'format' => FORMAT_PLAIN, 538 'itemid' => file_get_unused_draft_itemid(), 539 ] 540 ] 541 ); 542 $this->setUser($student2); 543 mod_assign_external::save_submission( 544 $assignmodule->id, 545 [ 546 'onlinetext_editor' => [ 547 'text' => 'Group 2, Submission 1', 548 'format' => FORMAT_PLAIN, 549 'itemid' => file_get_unused_draft_itemid(), 550 ] 551 ] 552 ); 553 mod_assign_external::submit_for_grading($assignmodule->id, 1); 554 $this->setUser($teacher); 555 mod_assign_external::save_grade($assignmodule->id, $student2->id, 0, -1, 1, "", 1); 556 $this->setUser($student2); 557 mod_assign_external::save_submission( 558 $assignmodule->id, 559 [ 560 'onlinetext_editor' => [ 561 'text' => 'Group 2, Submission 2', 562 'format' => FORMAT_PLAIN, 563 'itemid' => file_get_unused_draft_itemid(), 564 ] 565 ] 566 ); 567 568 $this->setUser($teacher); 569 $result = mod_assign_external::get_submissions([$assignmodule->id]); 570 $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result); 571 572 $this->assertEquals(1, count($result['assignments'])); 573 [$assignment] = $result['assignments']; 574 $this->assertEquals($assignmodule->id, $assignment['assignmentid']); 575 576 $this->assertEquals(2, count($assignment['submissions'])); 577 $expectedsubmissions = ['Group 1, Submission 1', 'Group 2, Submission 2']; 578 foreach ($assignment['submissions'] as $submission) { 579 $this->assertContains($submission['plugins'][0]['editorfields'][0]['text'], $expectedsubmissions); 580 } 581 } 582 583 /** 584 * Test get_user_flags 585 */ 586 public function test_get_user_flags() { 587 global $DB, $USER; 588 589 $this->resetAfterTest(true); 590 // Create a course and assignment. 591 $coursedata['idnumber'] = 'idnumbercourse'; 592 $coursedata['fullname'] = 'Lightwork Course'; 593 $coursedata['summary'] = 'Lightwork Course description'; 594 $coursedata['summaryformat'] = FORMAT_MOODLE; 595 $course = self::getDataGenerator()->create_course($coursedata); 596 597 $assigndata['course'] = $course->id; 598 $assigndata['name'] = 'lightwork assignment'; 599 600 $assign = self::getDataGenerator()->create_module('assign', $assigndata); 601 602 // Create a manual enrolment record. 603 $manualenroldata['enrol'] = 'manual'; 604 $manualenroldata['status'] = 0; 605 $manualenroldata['courseid'] = $course->id; 606 $enrolid = $DB->insert_record('enrol', $manualenroldata); 607 608 // Create a teacher and give them capabilities. 609 $context = context_course::instance($course->id); 610 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3); 611 $context = context_module::instance($assign->cmid); 612 $this->assignUserCapability('mod/assign:grade', $context->id, $roleid); 613 614 // Create the teacher's enrolment record. 615 $userenrolmentdata['status'] = 0; 616 $userenrolmentdata['enrolid'] = $enrolid; 617 $userenrolmentdata['userid'] = $USER->id; 618 $DB->insert_record('user_enrolments', $userenrolmentdata); 619 620 // Create a student and give them a user flag record. 621 $student = self::getDataGenerator()->create_user(); 622 $userflag = new stdClass(); 623 $userflag->assignment = $assign->id; 624 $userflag->userid = $student->id; 625 $userflag->locked = 0; 626 $userflag->mailed = 0; 627 $userflag->extensionduedate = 0; 628 $userflag->workflowstate = 'inmarking'; 629 $userflag->allocatedmarker = $USER->id; 630 631 $DB->insert_record('assign_user_flags', $userflag); 632 633 $assignmentids[] = $assign->id; 634 $result = mod_assign_external::get_user_flags($assignmentids); 635 636 // We need to execute the return values cleaning process to simulate the web service server. 637 $result = external_api::clean_returnvalue(mod_assign_external::get_user_flags_returns(), $result); 638 639 // Check that the correct user flag information for the student is returned. 640 $this->assertEquals(1, count($result['assignments'])); 641 $assignment = $result['assignments'][0]; 642 $this->assertEquals($assign->id, $assignment['assignmentid']); 643 // Should be one user flag record. 644 $this->assertEquals(1, count($assignment['userflags'])); 645 $userflag = $assignment['userflags'][0]; 646 $this->assertEquals($student->id, $userflag['userid']); 647 $this->assertEquals(0, $userflag['locked']); 648 $this->assertEquals(0, $userflag['mailed']); 649 $this->assertEquals(0, $userflag['extensionduedate']); 650 $this->assertEquals('inmarking', $userflag['workflowstate']); 651 $this->assertEquals($USER->id, $userflag['allocatedmarker']); 652 } 653 654 /** 655 * Test get_user_mappings 656 */ 657 public function test_get_user_mappings() { 658 global $DB, $USER; 659 660 $this->resetAfterTest(true); 661 // Create a course and assignment. 662 $coursedata['idnumber'] = 'idnumbercourse'; 663 $coursedata['fullname'] = 'Lightwork Course'; 664 $coursedata['summary'] = 'Lightwork Course description'; 665 $coursedata['summaryformat'] = FORMAT_MOODLE; 666 $course = self::getDataGenerator()->create_course($coursedata); 667 668 $assigndata['course'] = $course->id; 669 $assigndata['name'] = 'lightwork assignment'; 670 671 $assign = self::getDataGenerator()->create_module('assign', $assigndata); 672 673 // Create a manual enrolment record. 674 $manualenroldata['enrol'] = 'manual'; 675 $manualenroldata['status'] = 0; 676 $manualenroldata['courseid'] = $course->id; 677 $enrolid = $DB->insert_record('enrol', $manualenroldata); 678 679 // Create a teacher and give them capabilities. 680 $context = context_course::instance($course->id); 681 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3); 682 $context = context_module::instance($assign->cmid); 683 $this->assignUserCapability('mod/assign:revealidentities', $context->id, $roleid); 684 685 // Create the teacher's enrolment record. 686 $userenrolmentdata['status'] = 0; 687 $userenrolmentdata['enrolid'] = $enrolid; 688 $userenrolmentdata['userid'] = $USER->id; 689 $DB->insert_record('user_enrolments', $userenrolmentdata); 690 691 // Create a student and give them a user mapping record. 692 $student = self::getDataGenerator()->create_user(); 693 $mapping = new stdClass(); 694 $mapping->assignment = $assign->id; 695 $mapping->userid = $student->id; 696 697 $DB->insert_record('assign_user_mapping', $mapping); 698 699 $assignmentids[] = $assign->id; 700 $result = mod_assign_external::get_user_mappings($assignmentids); 701 702 // We need to execute the return values cleaning process to simulate the web service server. 703 $result = external_api::clean_returnvalue(mod_assign_external::get_user_mappings_returns(), $result); 704 705 // Check that the correct user mapping information for the student is returned. 706 $this->assertEquals(1, count($result['assignments'])); 707 $assignment = $result['assignments'][0]; 708 $this->assertEquals($assign->id, $assignment['assignmentid']); 709 // Should be one user mapping record. 710 $this->assertEquals(1, count($assignment['mappings'])); 711 $mapping = $assignment['mappings'][0]; 712 $this->assertEquals($student->id, $mapping['userid']); 713 } 714 715 /** 716 * Test lock_submissions 717 * 718 * @expectedException moodle_exception 719 */ 720 public function test_lock_submissions() { 721 global $DB, $USER; 722 723 $this->resetAfterTest(true); 724 // Create a course and assignment and users. 725 $course = self::getDataGenerator()->create_course(); 726 727 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 728 $params['course'] = $course->id; 729 $params['assignsubmission_onlinetext_enabled'] = 1; 730 $instance = $generator->create_instance($params); 731 $cm = get_coursemodule_from_instance('assign', $instance->id); 732 $context = context_module::instance($cm->id); 733 734 $assign = new assign($context, $cm, $course); 735 736 $student1 = self::getDataGenerator()->create_user(); 737 $student2 = self::getDataGenerator()->create_user(); 738 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 739 $this->getDataGenerator()->enrol_user($student1->id, 740 $course->id, 741 $studentrole->id); 742 $this->getDataGenerator()->enrol_user($student2->id, 743 $course->id, 744 $studentrole->id); 745 $teacher = self::getDataGenerator()->create_user(); 746 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); 747 $this->getDataGenerator()->enrol_user($teacher->id, 748 $course->id, 749 $teacherrole->id); 750 751 // Create a student1 with an online text submission. 752 // Simulate a submission. 753 $this->setUser($student1); 754 $submission = $assign->get_user_submission($student1->id, true); 755 $data = new stdClass(); 756 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(), 757 'text'=>'Submission text', 758 'format'=>FORMAT_MOODLE); 759 $plugin = $assign->get_submission_plugin_by_type('onlinetext'); 760 $plugin->save($submission, $data); 761 762 // Ready to test. 763 $this->setUser($teacher); 764 $students = array($student1->id, $student2->id); 765 $result = mod_assign_external::lock_submissions($instance->id, $students); 766 $result = external_api::clean_returnvalue(mod_assign_external::lock_submissions_returns(), $result); 767 768 // Check for 0 warnings. 769 $this->assertEquals(0, count($result)); 770 771 $this->setUser($student2); 772 $submission = $assign->get_user_submission($student2->id, true); 773 $data = new stdClass(); 774 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(), 775 'text'=>'Submission text', 776 'format'=>FORMAT_MOODLE); 777 $notices = array(); 778 $assign->save_submission($data, $notices); 779 } 780 781 /** 782 * Test unlock_submissions 783 */ 784 public function test_unlock_submissions() { 785 global $DB, $USER; 786 787 $this->resetAfterTest(true); 788 // Create a course and assignment and users. 789 $course = self::getDataGenerator()->create_course(); 790 791 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 792 $params['course'] = $course->id; 793 $params['assignsubmission_onlinetext_enabled'] = 1; 794 $instance = $generator->create_instance($params); 795 $cm = get_coursemodule_from_instance('assign', $instance->id); 796 $context = context_module::instance($cm->id); 797 798 $assign = new assign($context, $cm, $course); 799 800 $student1 = self::getDataGenerator()->create_user(); 801 $student2 = self::getDataGenerator()->create_user(); 802 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 803 $this->getDataGenerator()->enrol_user($student1->id, 804 $course->id, 805 $studentrole->id); 806 $this->getDataGenerator()->enrol_user($student2->id, 807 $course->id, 808 $studentrole->id); 809 $teacher = self::getDataGenerator()->create_user(); 810 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); 811 $this->getDataGenerator()->enrol_user($teacher->id, 812 $course->id, 813 $teacherrole->id); 814 815 // Create a student1 with an online text submission. 816 // Simulate a submission. 817 $this->setUser($student1); 818 $submission = $assign->get_user_submission($student1->id, true); 819 $data = new stdClass(); 820 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(), 821 'text'=>'Submission text', 822 'format'=>FORMAT_MOODLE); 823 $plugin = $assign->get_submission_plugin_by_type('onlinetext'); 824 $plugin->save($submission, $data); 825 826 // Ready to test. 827 $this->setUser($teacher); 828 $students = array($student1->id, $student2->id); 829 $result = mod_assign_external::lock_submissions($instance->id, $students); 830 $result = external_api::clean_returnvalue(mod_assign_external::lock_submissions_returns(), $result); 831 832 // Check for 0 warnings. 833 $this->assertEquals(0, count($result)); 834 835 $result = mod_assign_external::unlock_submissions($instance->id, $students); 836 $result = external_api::clean_returnvalue(mod_assign_external::unlock_submissions_returns(), $result); 837 838 // Check for 0 warnings. 839 $this->assertEquals(0, count($result)); 840 841 $this->setUser($student2); 842 $submission = $assign->get_user_submission($student2->id, true); 843 $data = new stdClass(); 844 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(), 845 'text'=>'Submission text', 846 'format'=>FORMAT_MOODLE); 847 $notices = array(); 848 $assign->save_submission($data, $notices); 849 } 850 851 /** 852 * Test submit_for_grading 853 */ 854 public function test_submit_for_grading() { 855 global $DB, $USER; 856 857 $this->resetAfterTest(true); 858 // Create a course and assignment and users. 859 $course = self::getDataGenerator()->create_course(); 860 861 set_config('submissionreceipts', 0, 'assign'); 862 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 863 $params['course'] = $course->id; 864 $params['assignsubmission_onlinetext_enabled'] = 1; 865 $params['submissiondrafts'] = 1; 866 $params['sendnotifications'] = 0; 867 $params['requiresubmissionstatement'] = 1; 868 $instance = $generator->create_instance($params); 869 $cm = get_coursemodule_from_instance('assign', $instance->id); 870 $context = context_module::instance($cm->id); 871 872 $assign = new assign($context, $cm, $course); 873 874 $student1 = self::getDataGenerator()->create_user(); 875 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 876 $this->getDataGenerator()->enrol_user($student1->id, 877 $course->id, 878 $studentrole->id); 879 880 // Create a student1 with an online text submission. 881 // Simulate a submission. 882 $this->setUser($student1); 883 $submission = $assign->get_user_submission($student1->id, true); 884 $data = new stdClass(); 885 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(), 886 'text'=>'Submission text', 887 'format'=>FORMAT_MOODLE); 888 $plugin = $assign->get_submission_plugin_by_type('onlinetext'); 889 $plugin->save($submission, $data); 890 891 $result = mod_assign_external::submit_for_grading($instance->id, false); 892 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result); 893 894 // Should be 1 fail because the submission statement was not aceptted. 895 $this->assertEquals(1, count($result)); 896 897 $result = mod_assign_external::submit_for_grading($instance->id, true); 898 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result); 899 900 // Check for 0 warnings. 901 $this->assertEquals(0, count($result)); 902 903 $submission = $assign->get_user_submission($student1->id, false); 904 905 $this->assertEquals(ASSIGN_SUBMISSION_STATUS_SUBMITTED, $submission->status); 906 } 907 908 /** 909 * Test save_user_extensions 910 */ 911 public function test_save_user_extensions() { 912 global $DB, $USER; 913 914 $this->resetAfterTest(true); 915 // Create a course and assignment and users. 916 $course = self::getDataGenerator()->create_course(); 917 918 $teacher = self::getDataGenerator()->create_user(); 919 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); 920 $this->getDataGenerator()->enrol_user($teacher->id, 921 $course->id, 922 $teacherrole->id); 923 $this->setUser($teacher); 924 925 $now = time(); 926 $yesterday = $now - 24*60*60; 927 $tomorrow = $now + 24*60*60; 928 set_config('submissionreceipts', 0, 'assign'); 929 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 930 $params['course'] = $course->id; 931 $params['submissiondrafts'] = 1; 932 $params['sendnotifications'] = 0; 933 $params['duedate'] = $yesterday; 934 $params['cutoffdate'] = $now - 10; 935 $instance = $generator->create_instance($params); 936 $cm = get_coursemodule_from_instance('assign', $instance->id); 937 $context = context_module::instance($cm->id); 938 939 $assign = new assign($context, $cm, $course); 940 941 $student1 = self::getDataGenerator()->create_user(); 942 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 943 $this->getDataGenerator()->enrol_user($student1->id, 944 $course->id, 945 $studentrole->id); 946 947 $this->setUser($student1); 948 $result = mod_assign_external::submit_for_grading($instance->id, true); 949 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result); 950 951 // Check for 0 warnings. 952 $this->assertEquals(1, count($result)); 953 954 $this->setUser($teacher); 955 $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow)); 956 $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result); 957 $this->assertEquals(1, count($result)); 958 959 $this->setUser($teacher); 960 $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($yesterday - 10)); 961 $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result); 962 $this->assertEquals(1, count($result)); 963 964 $this->setUser($teacher); 965 $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($tomorrow)); 966 $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result); 967 $this->assertEquals(0, count($result)); 968 969 $this->setUser($student1); 970 $result = mod_assign_external::submit_for_grading($instance->id, true); 971 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result); 972 $this->assertEquals(0, count($result)); 973 974 $this->setUser($student1); 975 $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow)); 976 $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result); 977 978 } 979 980 /** 981 * Test reveal_identities 982 * 983 * @expectedException required_capability_exception 984 */ 985 public function test_reveal_identities() { 986 global $DB, $USER; 987 988 $this->resetAfterTest(true); 989 // Create a course and assignment and users. 990 $course = self::getDataGenerator()->create_course(); 991 992 $teacher = self::getDataGenerator()->create_user(); 993 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); 994 $this->getDataGenerator()->enrol_user($teacher->id, 995 $course->id, 996 $teacherrole->id); 997 $this->setUser($teacher); 998 999 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1000 $params['course'] = $course->id; 1001 $params['submissiondrafts'] = 1; 1002 $params['sendnotifications'] = 0; 1003 $params['blindmarking'] = 1; 1004 $instance = $generator->create_instance($params); 1005 $cm = get_coursemodule_from_instance('assign', $instance->id); 1006 $context = context_module::instance($cm->id); 1007 1008 $assign = new assign($context, $cm, $course); 1009 1010 $student1 = self::getDataGenerator()->create_user(); 1011 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 1012 $this->getDataGenerator()->enrol_user($student1->id, 1013 $course->id, 1014 $studentrole->id); 1015 1016 $this->setUser($student1); 1017 $result = mod_assign_external::reveal_identities($instance->id); 1018 $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result); 1019 $this->assertEquals(1, count($result)); 1020 $this->assertEquals(true, $assign->is_blind_marking()); 1021 1022 $this->setUser($teacher); 1023 $result = mod_assign_external::reveal_identities($instance->id); 1024 $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result); 1025 $this->assertEquals(0, count($result)); 1026 $this->assertEquals(false, $assign->is_blind_marking()); 1027 1028 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1029 $params['course'] = $course->id; 1030 $params['submissiondrafts'] = 1; 1031 $params['sendnotifications'] = 0; 1032 $params['blindmarking'] = 0; 1033 $instance = $generator->create_instance($params); 1034 $cm = get_coursemodule_from_instance('assign', $instance->id); 1035 $context = context_module::instance($cm->id); 1036 1037 $assign = new assign($context, $cm, $course); 1038 $result = mod_assign_external::reveal_identities($instance->id); 1039 $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result); 1040 $this->assertEquals(1, count($result)); 1041 $this->assertEquals(false, $assign->is_blind_marking()); 1042 1043 } 1044 1045 /** 1046 * Test revert_submissions_to_draft 1047 */ 1048 public function test_revert_submissions_to_draft() { 1049 global $DB, $USER; 1050 1051 $this->resetAfterTest(true); 1052 set_config('submissionreceipts', 0, 'assign'); 1053 // Create a course and assignment and users. 1054 $course = self::getDataGenerator()->create_course(); 1055 1056 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1057 $params['course'] = $course->id; 1058 $params['sendnotifications'] = 0; 1059 $params['submissiondrafts'] = 1; 1060 $instance = $generator->create_instance($params); 1061 $cm = get_coursemodule_from_instance('assign', $instance->id); 1062 $context = context_module::instance($cm->id); 1063 1064 $assign = new assign($context, $cm, $course); 1065 1066 $student1 = self::getDataGenerator()->create_user(); 1067 $student2 = self::getDataGenerator()->create_user(); 1068 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 1069 $this->getDataGenerator()->enrol_user($student1->id, 1070 $course->id, 1071 $studentrole->id); 1072 $this->getDataGenerator()->enrol_user($student2->id, 1073 $course->id, 1074 $studentrole->id); 1075 $teacher = self::getDataGenerator()->create_user(); 1076 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); 1077 $this->getDataGenerator()->enrol_user($teacher->id, 1078 $course->id, 1079 $teacherrole->id); 1080 1081 // Create a student1 with an online text submission. 1082 // Simulate a submission. 1083 $this->setUser($student1); 1084 $result = mod_assign_external::submit_for_grading($instance->id, true); 1085 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result); 1086 $this->assertEquals(0, count($result)); 1087 1088 // Ready to test. 1089 $this->setUser($teacher); 1090 $students = array($student1->id, $student2->id); 1091 $result = mod_assign_external::revert_submissions_to_draft($instance->id, array($student1->id)); 1092 $result = external_api::clean_returnvalue(mod_assign_external::revert_submissions_to_draft_returns(), $result); 1093 1094 // Check for 0 warnings. 1095 $this->assertEquals(0, count($result)); 1096 1097 } 1098 1099 /** 1100 * Test save_submission 1101 */ 1102 public function test_save_submission() { 1103 global $DB, $USER; 1104 1105 $this->resetAfterTest(true); 1106 // Create a course and assignment and users. 1107 $course = self::getDataGenerator()->create_course(); 1108 1109 $teacher = self::getDataGenerator()->create_user(); 1110 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); 1111 $this->getDataGenerator()->enrol_user($teacher->id, 1112 $course->id, 1113 $teacherrole->id); 1114 $this->setUser($teacher); 1115 1116 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1117 $params['course'] = $course->id; 1118 $params['assignsubmission_onlinetext_enabled'] = 1; 1119 $params['assignsubmission_file_enabled'] = 1; 1120 $params['assignsubmission_file_maxfiles'] = 5; 1121 $params['assignsubmission_file_maxsizebytes'] = 1024*1024; 1122 $instance = $generator->create_instance($params); 1123 $cm = get_coursemodule_from_instance('assign', $instance->id); 1124 $context = context_module::instance($cm->id); 1125 1126 $assign = new assign($context, $cm, $course); 1127 1128 $student1 = self::getDataGenerator()->create_user(); 1129 $student2 = self::getDataGenerator()->create_user(); 1130 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 1131 $this->getDataGenerator()->enrol_user($student1->id, 1132 $course->id, 1133 $studentrole->id); 1134 $this->getDataGenerator()->enrol_user($student2->id, 1135 $course->id, 1136 $studentrole->id); 1137 // Create a student1 with an online text submission. 1138 // Simulate a submission. 1139 $this->setUser($student1); 1140 1141 // Create a file in a draft area. 1142 $draftidfile = file_get_unused_draft_itemid(); 1143 1144 $usercontext = context_user::instance($student1->id); 1145 $filerecord = array( 1146 'contextid' => $usercontext->id, 1147 'component' => 'user', 1148 'filearea' => 'draft', 1149 'itemid' => $draftidfile, 1150 'filepath' => '/', 1151 'filename' => 'testtext.txt', 1152 ); 1153 1154 $fs = get_file_storage(); 1155 $fs->create_file_from_string($filerecord, 'text contents'); 1156 1157 // Create another file in a different draft area. 1158 $draftidonlinetext = file_get_unused_draft_itemid(); 1159 1160 $filerecord = array( 1161 'contextid' => $usercontext->id, 1162 'component' => 'user', 1163 'filearea' => 'draft', 1164 'itemid' => $draftidonlinetext, 1165 'filepath' => '/', 1166 'filename' => 'shouldbeanimage.txt', 1167 ); 1168 1169 $fs->create_file_from_string($filerecord, 'image contents (not really)'); 1170 1171 // Now try a submission. 1172 $submissionpluginparams = array(); 1173 $submissionpluginparams['files_filemanager'] = $draftidfile; 1174 $onlinetexteditorparams = array('text' => '<p>Yeeha!</p>', 1175 'format'=>1, 1176 'itemid'=>$draftidonlinetext); 1177 $submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams; 1178 $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams); 1179 $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result); 1180 1181 $this->assertEquals(0, count($result)); 1182 1183 // Set up a due and cutoff passed date. 1184 $instance->duedate = time() - WEEKSECS; 1185 $instance->cutoffdate = time() - WEEKSECS; 1186 $DB->update_record('assign', $instance); 1187 1188 $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams); 1189 $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result); 1190 1191 $this->assertCount(1, $result); 1192 $this->assertEquals(get_string('duedatereached', 'assign'), $result[0]['item']); 1193 } 1194 1195 /** 1196 * Test save_grade 1197 */ 1198 public function test_save_grade() { 1199 global $DB, $USER; 1200 1201 $this->resetAfterTest(true); 1202 // Create a course and assignment and users. 1203 $course = self::getDataGenerator()->create_course(); 1204 1205 $teacher = self::getDataGenerator()->create_user(); 1206 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); 1207 $this->getDataGenerator()->enrol_user($teacher->id, 1208 $course->id, 1209 $teacherrole->id); 1210 $this->setUser($teacher); 1211 1212 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1213 $params['course'] = $course->id; 1214 $params['assignfeedback_file_enabled'] = 1; 1215 $params['assignfeedback_comments_enabled'] = 1; 1216 $instance = $generator->create_instance($params); 1217 $cm = get_coursemodule_from_instance('assign', $instance->id); 1218 $context = context_module::instance($cm->id); 1219 1220 $assign = new assign($context, $cm, $course); 1221 1222 $student1 = self::getDataGenerator()->create_user(); 1223 $student2 = self::getDataGenerator()->create_user(); 1224 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1225 $this->getDataGenerator()->enrol_user($student1->id, 1226 $course->id, 1227 $studentrole->id); 1228 $this->getDataGenerator()->enrol_user($student2->id, 1229 $course->id, 1230 $studentrole->id); 1231 // Simulate a grade. 1232 $this->setUser($teacher); 1233 1234 // Create a file in a draft area. 1235 $draftidfile = file_get_unused_draft_itemid(); 1236 1237 $usercontext = context_user::instance($teacher->id); 1238 $filerecord = array( 1239 'contextid' => $usercontext->id, 1240 'component' => 'user', 1241 'filearea' => 'draft', 1242 'itemid' => $draftidfile, 1243 'filepath' => '/', 1244 'filename' => 'testtext.txt', 1245 ); 1246 1247 $fs = get_file_storage(); 1248 $fs->create_file_from_string($filerecord, 'text contents'); 1249 1250 // Now try a grade. 1251 $feedbackpluginparams = array(); 1252 $feedbackpluginparams['files_filemanager'] = $draftidfile; 1253 $feedbackeditorparams = array('text' => 'Yeeha!', 1254 'format' => 1); 1255 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams; 1256 $result = mod_assign_external::save_grade($instance->id, 1257 $student1->id, 1258 50.0, 1259 -1, 1260 true, 1261 'released', 1262 false, 1263 $feedbackpluginparams); 1264 // No warnings. 1265 $this->assertNull($result); 1266 1267 $result = mod_assign_external::get_grades(array($instance->id)); 1268 $result = external_api::clean_returnvalue(mod_assign_external::get_grades_returns(), $result); 1269 1270 $this->assertEquals((float)$result['assignments'][0]['grades'][0]['grade'], '50.0'); 1271 } 1272 1273 /** 1274 * Test save grades with advanced grading data 1275 */ 1276 public function test_save_grades_with_advanced_grading() { 1277 global $DB, $USER; 1278 1279 $this->resetAfterTest(true); 1280 // Create a course and assignment and users. 1281 $course = self::getDataGenerator()->create_course(); 1282 1283 $teacher = self::getDataGenerator()->create_user(); 1284 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 1285 $this->getDataGenerator()->enrol_user($teacher->id, 1286 $course->id, 1287 $teacherrole->id); 1288 1289 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1290 $params['course'] = $course->id; 1291 $params['assignfeedback_file_enabled'] = 0; 1292 $params['assignfeedback_comments_enabled'] = 0; 1293 $instance = $generator->create_instance($params); 1294 $cm = get_coursemodule_from_instance('assign', $instance->id); 1295 $context = context_module::instance($cm->id); 1296 1297 $assign = new assign($context, $cm, $course); 1298 1299 $student1 = self::getDataGenerator()->create_user(); 1300 $student2 = self::getDataGenerator()->create_user(); 1301 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1302 $this->getDataGenerator()->enrol_user($student1->id, 1303 $course->id, 1304 $studentrole->id); 1305 $this->getDataGenerator()->enrol_user($student2->id, 1306 $course->id, 1307 $studentrole->id); 1308 1309 $this->setUser($teacher); 1310 1311 $feedbackpluginparams = array(); 1312 $feedbackpluginparams['files_filemanager'] = 0; 1313 $feedbackeditorparams = array('text' => '', 'format' => 1); 1314 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams; 1315 1316 // Create advanced grading data. 1317 // Create grading area. 1318 $gradingarea = array( 1319 'contextid' => $context->id, 1320 'component' => 'mod_assign', 1321 'areaname' => 'submissions', 1322 'activemethod' => 'rubric' 1323 ); 1324 $areaid = $DB->insert_record('grading_areas', $gradingarea); 1325 1326 // Create a rubric grading definition. 1327 $rubricdefinition = array ( 1328 'areaid' => $areaid, 1329 'method' => 'rubric', 1330 'name' => 'test', 1331 'status' => 20, 1332 'copiedfromid' => 1, 1333 'timecreated' => 1, 1334 'usercreated' => $teacher->id, 1335 'timemodified' => 1, 1336 'usermodified' => $teacher->id, 1337 'timecopied' => 0 1338 ); 1339 $definitionid = $DB->insert_record('grading_definitions', $rubricdefinition); 1340 1341 // Create a criterion with a level. 1342 $rubriccriteria = array ( 1343 'definitionid' => $definitionid, 1344 'sortorder' => 1, 1345 'description' => 'Demonstrate an understanding of disease control', 1346 'descriptionformat' => 0 1347 ); 1348 $criterionid = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria); 1349 $rubriclevel1 = array ( 1350 'criterionid' => $criterionid, 1351 'score' => 50, 1352 'definition' => 'pass', 1353 'definitionformat' => 0 1354 ); 1355 $rubriclevel2 = array ( 1356 'criterionid' => $criterionid, 1357 'score' => 100, 1358 'definition' => 'excellent', 1359 'definitionformat' => 0 1360 ); 1361 $rubriclevel3 = array ( 1362 'criterionid' => $criterionid, 1363 'score' => 0, 1364 'definition' => 'fail', 1365 'definitionformat' => 0 1366 ); 1367 $levelid1 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel1); 1368 $levelid2 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel2); 1369 $levelid3 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel3); 1370 1371 // Create the filling. 1372 $student1filling = array ( 1373 'criterionid' => $criterionid, 1374 'levelid' => $levelid1, 1375 'remark' => 'well done you passed', 1376 'remarkformat' => 0 1377 ); 1378 1379 $student2filling = array ( 1380 'criterionid' => $criterionid, 1381 'levelid' => $levelid2, 1382 'remark' => 'Excellent work', 1383 'remarkformat' => 0 1384 ); 1385 1386 $student1criteria = array(array('criterionid' => $criterionid, 'fillings' => array($student1filling))); 1387 $student1advancedgradingdata = array('rubric' => array('criteria' => $student1criteria)); 1388 1389 $student2criteria = array(array('criterionid' => $criterionid, 'fillings' => array($student2filling))); 1390 $student2advancedgradingdata = array('rubric' => array('criteria' => $student2criteria)); 1391 1392 $grades = array(); 1393 $student1gradeinfo = array(); 1394 $student1gradeinfo['userid'] = $student1->id; 1395 $student1gradeinfo['grade'] = 0; // Ignored since advanced grading is being used. 1396 $student1gradeinfo['attemptnumber'] = -1; 1397 $student1gradeinfo['addattempt'] = true; 1398 $student1gradeinfo['workflowstate'] = 'released'; 1399 $student1gradeinfo['plugindata'] = $feedbackpluginparams; 1400 $student1gradeinfo['advancedgradingdata'] = $student1advancedgradingdata; 1401 $grades[] = $student1gradeinfo; 1402 1403 $student2gradeinfo = array(); 1404 $student2gradeinfo['userid'] = $student2->id; 1405 $student2gradeinfo['grade'] = 0; // Ignored since advanced grading is being used. 1406 $student2gradeinfo['attemptnumber'] = -1; 1407 $student2gradeinfo['addattempt'] = true; 1408 $student2gradeinfo['workflowstate'] = 'released'; 1409 $student2gradeinfo['plugindata'] = $feedbackpluginparams; 1410 $student2gradeinfo['advancedgradingdata'] = $student2advancedgradingdata; 1411 $grades[] = $student2gradeinfo; 1412 1413 $result = mod_assign_external::save_grades($instance->id, false, $grades); 1414 $this->assertNull($result); 1415 1416 $student1grade = $DB->get_record('assign_grades', 1417 array('userid' => $student1->id, 'assignment' => $instance->id), 1418 '*', 1419 MUST_EXIST); 1420 $this->assertEquals((float)$student1grade->grade, '50.0'); 1421 1422 $student2grade = $DB->get_record('assign_grades', 1423 array('userid' => $student2->id, 'assignment' => $instance->id), 1424 '*', 1425 MUST_EXIST); 1426 $this->assertEquals((float)$student2grade->grade, '100.0'); 1427 } 1428 1429 /** 1430 * Test save grades for a team submission 1431 * 1432 * @expectedException invalid_parameter_exception 1433 */ 1434 public function test_save_grades_with_group_submission() { 1435 global $DB, $USER, $CFG; 1436 require_once($CFG->dirroot . '/group/lib.php'); 1437 1438 $this->resetAfterTest(true); 1439 // Create a course and assignment and users. 1440 $course = self::getDataGenerator()->create_course(); 1441 1442 $teacher = self::getDataGenerator()->create_user(); 1443 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 1444 $this->getDataGenerator()->enrol_user($teacher->id, 1445 $course->id, 1446 $teacherrole->id); 1447 1448 $groupingdata = array(); 1449 $groupingdata['courseid'] = $course->id; 1450 $groupingdata['name'] = 'Group assignment grouping'; 1451 1452 $grouping = self::getDataGenerator()->create_grouping($groupingdata); 1453 1454 $group1data = array(); 1455 $group1data['courseid'] = $course->id; 1456 $group1data['name'] = 'Team 1'; 1457 $group2data = array(); 1458 $group2data['courseid'] = $course->id; 1459 $group2data['name'] = 'Team 2'; 1460 1461 $group1 = self::getDataGenerator()->create_group($group1data); 1462 $group2 = self::getDataGenerator()->create_group($group2data); 1463 1464 groups_assign_grouping($grouping->id, $group1->id); 1465 groups_assign_grouping($grouping->id, $group2->id); 1466 1467 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1468 $params['course'] = $course->id; 1469 $params['teamsubmission'] = 1; 1470 $params['teamsubmissiongroupingid'] = $grouping->id; 1471 $instance = $generator->create_instance($params); 1472 $cm = get_coursemodule_from_instance('assign', $instance->id); 1473 $context = context_module::instance($cm->id); 1474 1475 $assign = new assign($context, $cm, $course); 1476 1477 $student1 = self::getDataGenerator()->create_user(); 1478 $student2 = self::getDataGenerator()->create_user(); 1479 $student3 = self::getDataGenerator()->create_user(); 1480 $student4 = self::getDataGenerator()->create_user(); 1481 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1482 $this->getDataGenerator()->enrol_user($student1->id, 1483 $course->id, 1484 $studentrole->id); 1485 $this->getDataGenerator()->enrol_user($student2->id, 1486 $course->id, 1487 $studentrole->id); 1488 $this->getDataGenerator()->enrol_user($student3->id, 1489 $course->id, 1490 $studentrole->id); 1491 $this->getDataGenerator()->enrol_user($student4->id, 1492 $course->id, 1493 $studentrole->id); 1494 1495 groups_add_member($group1->id, $student1->id); 1496 groups_add_member($group1->id, $student2->id); 1497 groups_add_member($group1->id, $student3->id); 1498 groups_add_member($group2->id, $student4->id); 1499 $this->setUser($teacher); 1500 1501 $feedbackpluginparams = array(); 1502 $feedbackpluginparams['files_filemanager'] = 0; 1503 $feedbackeditorparams = array('text' => '', 'format' => 1); 1504 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams; 1505 1506 $grades1 = array(); 1507 $student1gradeinfo = array(); 1508 $student1gradeinfo['userid'] = $student1->id; 1509 $student1gradeinfo['grade'] = 50; 1510 $student1gradeinfo['attemptnumber'] = -1; 1511 $student1gradeinfo['addattempt'] = true; 1512 $student1gradeinfo['workflowstate'] = 'released'; 1513 $student1gradeinfo['plugindata'] = $feedbackpluginparams; 1514 $grades1[] = $student1gradeinfo; 1515 1516 $student2gradeinfo = array(); 1517 $student2gradeinfo['userid'] = $student2->id; 1518 $student2gradeinfo['grade'] = 75; 1519 $student2gradeinfo['attemptnumber'] = -1; 1520 $student2gradeinfo['addattempt'] = true; 1521 $student2gradeinfo['workflowstate'] = 'released'; 1522 $student2gradeinfo['plugindata'] = $feedbackpluginparams; 1523 $grades1[] = $student2gradeinfo; 1524 1525 // Expect an exception since 2 grades have been submitted for the same team. 1526 $result = mod_assign_external::save_grades($instance->id, true, $grades1); 1527 $result = external_api::clean_returnvalue(mod_assign_external::save_grades_returns(), $result); 1528 1529 $grades2 = array(); 1530 $student3gradeinfo = array(); 1531 $student3gradeinfo['userid'] = $student3->id; 1532 $student3gradeinfo['grade'] = 50; 1533 $student3gradeinfo['attemptnumber'] = -1; 1534 $student3gradeinfo['addattempt'] = true; 1535 $student3gradeinfo['workflowstate'] = 'released'; 1536 $student3gradeinfo['plugindata'] = $feedbackpluginparams; 1537 $grades2[] = $student3gradeinfo; 1538 1539 $student4gradeinfo = array(); 1540 $student4gradeinfo['userid'] = $student4->id; 1541 $student4gradeinfo['grade'] = 75; 1542 $student4gradeinfo['attemptnumber'] = -1; 1543 $student4gradeinfo['addattempt'] = true; 1544 $student4gradeinfo['workflowstate'] = 'released'; 1545 $student4gradeinfo['plugindata'] = $feedbackpluginparams; 1546 $grades2[] = $student4gradeinfo; 1547 $result = mod_assign_external::save_grades($instance->id, true, $grades2); 1548 $result = external_api::clean_returnvalue(mod_assign_external::save_grades_returns(), $result); 1549 // There should be no warnings. 1550 $this->assertEquals(0, count($result)); 1551 1552 $student3grade = $DB->get_record('assign_grades', 1553 array('userid' => $student3->id, 'assignment' => $instance->id), 1554 '*', 1555 MUST_EXIST); 1556 $this->assertEquals($student3grade->grade, '50.0'); 1557 1558 $student4grade = $DB->get_record('assign_grades', 1559 array('userid' => $student4->id, 'assignment' => $instance->id), 1560 '*', 1561 MUST_EXIST); 1562 $this->assertEquals($student4grade->grade, '75.0'); 1563 } 1564 1565 /** 1566 * Test copy_previous_attempt 1567 */ 1568 public function test_copy_previous_attempt() { 1569 global $DB, $USER; 1570 1571 $this->resetAfterTest(true); 1572 // Create a course and assignment and users. 1573 $course = self::getDataGenerator()->create_course(); 1574 1575 $teacher = self::getDataGenerator()->create_user(); 1576 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher')); 1577 $this->getDataGenerator()->enrol_user($teacher->id, 1578 $course->id, 1579 $teacherrole->id); 1580 $this->setUser($teacher); 1581 1582 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1583 $params['course'] = $course->id; 1584 $params['assignsubmission_onlinetext_enabled'] = 1; 1585 $params['assignsubmission_file_enabled'] = 0; 1586 $params['assignfeedback_file_enabled'] = 0; 1587 $params['attemptreopenmethod'] = 'manual'; 1588 $params['maxattempts'] = 5; 1589 $instance = $generator->create_instance($params); 1590 $cm = get_coursemodule_from_instance('assign', $instance->id); 1591 $context = context_module::instance($cm->id); 1592 1593 $assign = new assign($context, $cm, $course); 1594 1595 $student1 = self::getDataGenerator()->create_user(); 1596 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 1597 $this->getDataGenerator()->enrol_user($student1->id, 1598 $course->id, 1599 $studentrole->id); 1600 // Now try a submission. 1601 $this->setUser($student1); 1602 $draftidonlinetext = file_get_unused_draft_itemid(); 1603 $submissionpluginparams = array(); 1604 $onlinetexteditorparams = array('text'=>'Yeeha!', 1605 'format'=>1, 1606 'itemid'=>$draftidonlinetext); 1607 $submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams; 1608 $submissionpluginparams['files_filemanager'] = file_get_unused_draft_itemid(); 1609 $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams); 1610 $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result); 1611 1612 $this->setUser($teacher); 1613 // Add a grade and reopen the attempt. 1614 // Now try a grade. 1615 $feedbackpluginparams = array(); 1616 $feedbackpluginparams['files_filemanager'] = file_get_unused_draft_itemid(); 1617 $feedbackeditorparams = array('text'=>'Yeeha!', 1618 'format'=>1); 1619 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams; 1620 $result = mod_assign_external::save_grade($instance->id, 1621 $student1->id, 1622 50.0, 1623 -1, 1624 true, 1625 'released', 1626 false, 1627 $feedbackpluginparams); 1628 $this->assertNull($result); 1629 1630 $this->setUser($student1); 1631 // Now copy the previous attempt. 1632 $result = mod_assign_external::copy_previous_attempt($instance->id); 1633 $result = external_api::clean_returnvalue(mod_assign_external::copy_previous_attempt_returns(), $result); 1634 // No warnings. 1635 $this->assertEquals(0, count($result)); 1636 1637 $this->setUser($teacher); 1638 $result = mod_assign_external::get_submissions(array($instance->id)); 1639 $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result); 1640 1641 // Check we are now on the second attempt. 1642 $this->assertEquals($result['assignments'][0]['submissions'][0]['attemptnumber'], 1); 1643 // Check the plugins data is not empty. 1644 $this->assertNotEmpty($result['assignments'][0]['submissions'][0]['plugins']); 1645 1646 } 1647 1648 /** 1649 * Test set_user_flags 1650 */ 1651 public function test_set_user_flags() { 1652 global $DB, $USER; 1653 1654 $this->resetAfterTest(true); 1655 // Create a course and assignment. 1656 $coursedata['idnumber'] = 'idnumbercourse'; 1657 $coursedata['fullname'] = 'Lightwork Course'; 1658 $coursedata['summary'] = 'Lightwork Course description'; 1659 $coursedata['summaryformat'] = FORMAT_MOODLE; 1660 $course = self::getDataGenerator()->create_course($coursedata); 1661 1662 $assigndata['course'] = $course->id; 1663 $assigndata['name'] = 'lightwork assignment'; 1664 1665 $assign = self::getDataGenerator()->create_module('assign', $assigndata); 1666 1667 // Create a manual enrolment record. 1668 $manualenroldata['enrol'] = 'manual'; 1669 $manualenroldata['status'] = 0; 1670 $manualenroldata['courseid'] = $course->id; 1671 $enrolid = $DB->insert_record('enrol', $manualenroldata); 1672 1673 // Create a teacher and give them capabilities. 1674 $context = context_course::instance($course->id); 1675 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3); 1676 $context = context_module::instance($assign->cmid); 1677 $this->assignUserCapability('mod/assign:grade', $context->id, $roleid); 1678 1679 // Create the teacher's enrolment record. 1680 $userenrolmentdata['status'] = 0; 1681 $userenrolmentdata['enrolid'] = $enrolid; 1682 $userenrolmentdata['userid'] = $USER->id; 1683 $DB->insert_record('user_enrolments', $userenrolmentdata); 1684 1685 // Create a student. 1686 $student = self::getDataGenerator()->create_user(); 1687 1688 // Create test user flags record. 1689 $userflags = array(); 1690 $userflag['userid'] = $student->id; 1691 $userflag['workflowstate'] = 'inmarking'; 1692 $userflag['allocatedmarker'] = $USER->id; 1693 $userflags = array($userflag); 1694 1695 $createduserflags = mod_assign_external::set_user_flags($assign->id, $userflags); 1696 // We need to execute the return values cleaning process to simulate the web service server. 1697 $createduserflags = external_api::clean_returnvalue(mod_assign_external::set_user_flags_returns(), $createduserflags); 1698 1699 $this->assertEquals($student->id, $createduserflags[0]['userid']); 1700 $createduserflag = $DB->get_record('assign_user_flags', array('id' => $createduserflags[0]['id'])); 1701 1702 // Confirm that all data was inserted correctly. 1703 $this->assertEquals($student->id, $createduserflag->userid); 1704 $this->assertEquals($assign->id, $createduserflag->assignment); 1705 $this->assertEquals(0, $createduserflag->locked); 1706 $this->assertEquals(2, $createduserflag->mailed); 1707 $this->assertEquals(0, $createduserflag->extensionduedate); 1708 $this->assertEquals('inmarking', $createduserflag->workflowstate); 1709 $this->assertEquals($USER->id, $createduserflag->allocatedmarker); 1710 1711 // Create update data. 1712 $userflags = array(); 1713 $userflag['userid'] = $createduserflag->userid; 1714 $userflag['workflowstate'] = 'readyforreview'; 1715 $userflags = array($userflag); 1716 1717 $updateduserflags = mod_assign_external::set_user_flags($assign->id, $userflags); 1718 // We need to execute the return values cleaning process to simulate the web service server. 1719 $updateduserflags = external_api::clean_returnvalue(mod_assign_external::set_user_flags_returns(), $updateduserflags); 1720 1721 $this->assertEquals($student->id, $updateduserflags[0]['userid']); 1722 $updateduserflag = $DB->get_record('assign_user_flags', array('id' => $updateduserflags[0]['id'])); 1723 1724 // Confirm that all data was updated correctly. 1725 $this->assertEquals($student->id, $updateduserflag->userid); 1726 $this->assertEquals($assign->id, $updateduserflag->assignment); 1727 $this->assertEquals(0, $updateduserflag->locked); 1728 $this->assertEquals(2, $updateduserflag->mailed); 1729 $this->assertEquals(0, $updateduserflag->extensionduedate); 1730 $this->assertEquals('readyforreview', $updateduserflag->workflowstate); 1731 $this->assertEquals($USER->id, $updateduserflag->allocatedmarker); 1732 } 1733 1734 /** 1735 * Test view_grading_table 1736 * 1737 * @expectedException dml_missing_record_exception 1738 */ 1739 public function test_view_grading_table_invalid_instance() { 1740 global $DB; 1741 1742 $this->resetAfterTest(true); 1743 1744 // Setup test data. 1745 $course = $this->getDataGenerator()->create_course(); 1746 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 1747 $context = context_module::instance($assign->cmid); 1748 $cm = get_coursemodule_from_instance('assign', $assign->id); 1749 1750 // Test invalid instance id. 1751 mod_assign_external::view_grading_table(0); 1752 } 1753 1754 /** 1755 * Test view_grading_table 1756 * 1757 * @expectedException require_login_exception 1758 */ 1759 public function test_view_grading_table_not_enrolled() { 1760 global $DB; 1761 1762 $this->resetAfterTest(true); 1763 1764 // Setup test data. 1765 $course = $this->getDataGenerator()->create_course(); 1766 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 1767 $context = context_module::instance($assign->cmid); 1768 $cm = get_coursemodule_from_instance('assign', $assign->id); 1769 1770 // Test not-enrolled user. 1771 $user = self::getDataGenerator()->create_user(); 1772 $this->setUser($user); 1773 1774 mod_assign_external::view_grading_table($assign->id); 1775 } 1776 1777 /** 1778 * Test view_grading_table 1779 */ 1780 public function test_view_grading_table_correct() { 1781 global $DB; 1782 1783 $this->resetAfterTest(true); 1784 1785 // Setup test data. 1786 $course = $this->getDataGenerator()->create_course(); 1787 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 1788 $context = context_module::instance($assign->cmid); 1789 $cm = get_coursemodule_from_instance('assign', $assign->id); 1790 1791 // Test user with full capabilities. 1792 $user = self::getDataGenerator()->create_user(); 1793 $this->setUser($user); 1794 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 1795 $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id); 1796 1797 // Trigger and capture the event. 1798 $sink = $this->redirectEvents(); 1799 1800 $result = mod_assign_external::view_grading_table($assign->id); 1801 $result = external_api::clean_returnvalue(mod_assign_external::view_grading_table_returns(), $result); 1802 1803 $events = $sink->get_events(); 1804 $this->assertCount(1, $events); 1805 $event = array_shift($events); 1806 1807 // Checking that the event contains the expected values. 1808 $this->assertInstanceOf('\mod_assign\event\grading_table_viewed', $event); 1809 $this->assertEquals($context, $event->get_context()); 1810 $moodleurl = new \moodle_url('/mod/assign/view.php', array('id' => $cm->id)); 1811 $this->assertEquals($moodleurl, $event->get_url()); 1812 $this->assertEventContextNotUsed($event); 1813 $this->assertNotEmpty($event->get_name()); 1814 } 1815 1816 /** 1817 * Test view_grading_table 1818 * 1819 * @expectedException require_login_exception 1820 * @expectedExceptionMessage Course or activity not accessible. (Activity is hidden) 1821 */ 1822 public function test_view_grading_table_without_capability() { 1823 global $DB; 1824 1825 $this->resetAfterTest(true); 1826 1827 // Setup test data. 1828 $course = $this->getDataGenerator()->create_course(); 1829 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 1830 $context = context_module::instance($assign->cmid); 1831 $cm = get_coursemodule_from_instance('assign', $assign->id); 1832 1833 // Test user with no capabilities. 1834 $user = self::getDataGenerator()->create_user(); 1835 $this->setUser($user); 1836 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 1837 $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id); 1838 1839 // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles. 1840 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 1841 assign_capability('mod/assign:view', CAP_PROHIBIT, $teacherrole->id, $context->id); 1842 // Empty all the caches that may be affected by this change. 1843 accesslib_clear_all_caches_for_unit_testing(); 1844 course_modinfo::clear_instance_cache(); 1845 1846 mod_assign_external::view_grading_table($assign->id); 1847 } 1848 1849 /** 1850 * Test subplugins availability 1851 */ 1852 public function test_subplugins_availability() { 1853 global $CFG; 1854 1855 require_once($CFG->dirroot . '/mod/assign/adminlib.php'); 1856 $this->resetAfterTest(true); 1857 1858 // Hide assignment file submissiong plugin. 1859 $pluginmanager = new assign_plugin_manager('assignsubmission'); 1860 $pluginmanager->hide_plugin('file'); 1861 $parameters = mod_assign_external::save_submission_parameters(); 1862 1863 $this->assertTrue(!isset($parameters->keys['plugindata']->keys['files_filemanager'])); 1864 1865 // Show it again and check that the value is returned as optional. 1866 $pluginmanager->show_plugin('file'); 1867 $parameters = mod_assign_external::save_submission_parameters(); 1868 $this->assertTrue(isset($parameters->keys['plugindata']->keys['files_filemanager'])); 1869 $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['files_filemanager']->required); 1870 1871 // Hide feedback file submissiong plugin. 1872 $pluginmanager = new assign_plugin_manager('assignfeedback'); 1873 $pluginmanager->hide_plugin('file'); 1874 1875 $parameters = mod_assign_external::save_grade_parameters(); 1876 1877 $this->assertTrue(!isset($parameters->keys['plugindata']->keys['files_filemanager'])); 1878 1879 // Show it again and check that the value is returned as optional. 1880 $pluginmanager->show_plugin('file'); 1881 $parameters = mod_assign_external::save_grade_parameters(); 1882 1883 $this->assertTrue(isset($parameters->keys['plugindata']->keys['files_filemanager'])); 1884 $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['files_filemanager']->required); 1885 1886 // Check a different one. 1887 $pluginmanager->show_plugin('comments'); 1888 $this->assertTrue(isset($parameters->keys['plugindata']->keys['assignfeedbackcomments_editor'])); 1889 $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['assignfeedbackcomments_editor']->required); 1890 } 1891 1892 /** 1893 * Test test_view_submission_status 1894 */ 1895 public function test_view_submission_status() { 1896 global $DB; 1897 1898 $this->resetAfterTest(true); 1899 1900 $this->setAdminUser(); 1901 // Setup test data. 1902 $course = $this->getDataGenerator()->create_course(); 1903 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id)); 1904 $context = context_module::instance($assign->cmid); 1905 $cm = get_coursemodule_from_instance('assign', $assign->id); 1906 1907 // Test invalid instance id. 1908 try { 1909 mod_assign_external::view_submission_status(0); 1910 $this->fail('Exception expected due to invalid mod_assign instance id.'); 1911 } catch (moodle_exception $e) { 1912 $this->assertEquals('invalidrecord', $e->errorcode); 1913 } 1914 1915 // Test not-enrolled user. 1916 $user = self::getDataGenerator()->create_user(); 1917 $this->setUser($user); 1918 try { 1919 mod_assign_external::view_submission_status($assign->id); 1920 $this->fail('Exception expected due to not enrolled user.'); 1921 } catch (moodle_exception $e) { 1922 $this->assertEquals('requireloginerror', $e->errorcode); 1923 } 1924 1925 // Test user with full capabilities. 1926 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1927 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id); 1928 1929 // Trigger and capture the event. 1930 $sink = $this->redirectEvents(); 1931 1932 $result = mod_assign_external::view_submission_status($assign->id); 1933 $result = external_api::clean_returnvalue(mod_assign_external::view_submission_status_returns(), $result); 1934 1935 $events = $sink->get_events(); 1936 $this->assertCount(1, $events); 1937 $event = array_shift($events); 1938 1939 // Checking that the event contains the expected values. 1940 $this->assertInstanceOf('\mod_assign\event\submission_status_viewed', $event); 1941 $this->assertEquals($context, $event->get_context()); 1942 $moodleurl = new \moodle_url('/mod/assign/view.php', array('id' => $cm->id)); 1943 $this->assertEquals($moodleurl, $event->get_url()); 1944 $this->assertEventContextNotUsed($event); 1945 $this->assertNotEmpty($event->get_name()); 1946 1947 // Test user with no capabilities. 1948 // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles. 1949 assign_capability('mod/assign:view', CAP_PROHIBIT, $studentrole->id, $context->id); 1950 accesslib_clear_all_caches_for_unit_testing(); 1951 course_modinfo::clear_instance_cache(); 1952 1953 try { 1954 mod_assign_external::view_submission_status($assign->id); 1955 $this->fail('Exception expected due to missing capability.'); 1956 } catch (moodle_exception $e) { 1957 $this->assertEquals('requireloginerror', $e->errorcode); 1958 } 1959 } 1960 1961 /** 1962 * Create a submission for testing the get_submission_status function. 1963 * @param boolean $submitforgrading whether to submit for grading the submission 1964 * @return array an array containing all the required data for testing 1965 */ 1966 private function create_submission_for_testing_status($submitforgrading = false) { 1967 global $DB; 1968 1969 // Create a course and assignment and users. 1970 $course = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1)); 1971 1972 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 1973 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 1974 1975 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1976 $params = array( 1977 'course' => $course->id, 1978 'assignsubmission_file_maxfiles' => 1, 1979 'assignsubmission_file_maxsizebytes' => 1024 * 1024, 1980 'assignsubmission_onlinetext_enabled' => 1, 1981 'assignsubmission_file_enabled' => 1, 1982 'submissiondrafts' => 1, 1983 'assignfeedback_file_enabled' => 1, 1984 'assignfeedback_comments_enabled' => 1, 1985 'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL, 1986 'sendnotifications' => 0 1987 ); 1988 1989 set_config('submissionreceipts', 0, 'assign'); 1990 1991 $instance = $generator->create_instance($params); 1992 $cm = get_coursemodule_from_instance('assign', $instance->id); 1993 $context = context_module::instance($cm->id); 1994 1995 $assign = new mod_assign_testable_assign($context, $cm, $course); 1996 1997 $student1 = self::getDataGenerator()->create_user(); 1998 $student2 = self::getDataGenerator()->create_user(); 1999 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 2000 $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id); 2001 $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id); 2002 $teacher = self::getDataGenerator()->create_user(); 2003 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 2004 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); 2005 2006 $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student1->id)); 2007 $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $teacher->id)); 2008 $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $student2->id)); 2009 $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $teacher->id)); 2010 2011 $this->setUser($student1); 2012 2013 // Create a student1 with an online text submission. 2014 // Simulate a submission. 2015 $submission = $assign->get_user_submission($student1->id, true); 2016 2017 $data = new stdClass(); 2018 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(), 2019 'text' => 'Submission text with a <a href="@@PLUGINFILE@@/intro.txt">link</a>', 2020 'format' => FORMAT_MOODLE); 2021 2022 $draftidfile = file_get_unused_draft_itemid(); 2023 $usercontext = context_user::instance($student1->id); 2024 $filerecord = array( 2025 'contextid' => $usercontext->id, 2026 'component' => 'user', 2027 'filearea' => 'draft', 2028 'itemid' => $draftidfile, 2029 'filepath' => '/', 2030 'filename' => 't.txt', 2031 ); 2032 $fs = get_file_storage(); 2033 $fs->create_file_from_string($filerecord, 'text contents'); 2034 2035 $data->files_filemanager = $draftidfile; 2036 2037 $notices = array(); 2038 $assign->save_submission($data, $notices); 2039 2040 if ($submitforgrading) { 2041 // Now, submit the draft for grading. 2042 $notices = array(); 2043 2044 $data = new stdClass; 2045 $data->userid = $student1->id; 2046 $assign->submit_for_grading($data, $notices); 2047 } 2048 2049 return array($assign, $instance, $student1, $student2, $teacher, $group1, $group2); 2050 } 2051 2052 /** 2053 * Test get_submission_status for a draft submission. 2054 */ 2055 public function test_get_submission_status_in_draft_status() { 2056 $this->resetAfterTest(true); 2057 2058 list($assign, $instance, $student1, $student2, $teacher, $g1, $g2) = $this->create_submission_for_testing_status(); 2059 $studentsubmission = $assign->get_user_submission($student1->id, true); 2060 2061 $result = mod_assign_external::get_submission_status($assign->get_instance()->id); 2062 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request. 2063 $this->assertDebuggingCalled(); 2064 2065 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2066 2067 // The submission is now in draft mode. 2068 $this->assertCount(0, $result['warnings']); 2069 $this->assertFalse(isset($result['gradingsummary'])); 2070 $this->assertFalse(isset($result['feedback'])); 2071 $this->assertFalse(isset($result['previousattempts'])); 2072 2073 $this->assertTrue($result['lastattempt']['submissionsenabled']); 2074 $this->assertTrue($result['lastattempt']['canedit']); 2075 $this->assertTrue($result['lastattempt']['cansubmit']); 2076 $this->assertFalse($result['lastattempt']['locked']); 2077 $this->assertFalse($result['lastattempt']['graded']); 2078 $this->assertEmpty($result['lastattempt']['extensionduedate']); 2079 $this->assertFalse($result['lastattempt']['blindmarking']); 2080 $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']); 2081 $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']); 2082 2083 $this->assertEquals($student1->id, $result['lastattempt']['submission']['userid']); 2084 $this->assertEquals(0, $result['lastattempt']['submission']['attemptnumber']); 2085 $this->assertEquals('draft', $result['lastattempt']['submission']['status']); 2086 $this->assertEquals(0, $result['lastattempt']['submission']['groupid']); 2087 $this->assertEquals($assign->get_instance()->id, $result['lastattempt']['submission']['assignment']); 2088 $this->assertEquals(1, $result['lastattempt']['submission']['latest']); 2089 2090 // Map plugins based on their type - we can't rely on them being in a 2091 // particular order, especially if 3rd party plugins are installed. 2092 $submissionplugins = array(); 2093 foreach ($result['lastattempt']['submission']['plugins'] as $plugin) { 2094 $submissionplugins[$plugin['type']] = $plugin; 2095 } 2096 2097 // Format expected online text. 2098 $onlinetext = 'Submission text with a <a href="@@PLUGINFILE@@/intro.txt">link</a>'; 2099 list($expectedtext, $expectedformat) = external_format_text($onlinetext, FORMAT_HTML, $assign->get_context()->id, 2100 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $studentsubmission->id); 2101 2102 $this->assertEquals($expectedtext, $submissionplugins['onlinetext']['editorfields'][0]['text']); 2103 $this->assertEquals($expectedformat, $submissionplugins['onlinetext']['editorfields'][0]['format']); 2104 $this->assertEquals('/', $submissionplugins['file']['fileareas'][0]['files'][0]['filepath']); 2105 $this->assertEquals('t.txt', $submissionplugins['file']['fileareas'][0]['files'][0]['filename']); 2106 } 2107 2108 /** 2109 * Test get_submission_status for a submitted submission. 2110 */ 2111 public function test_get_submission_status_in_submission_status() { 2112 $this->resetAfterTest(true); 2113 2114 list($assign, $instance, $student1, $student2, $teacher, $g1, $g2) = $this->create_submission_for_testing_status(true); 2115 2116 $result = mod_assign_external::get_submission_status($assign->get_instance()->id); 2117 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request. 2118 $this->assertDebuggingCalled(); 2119 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2120 2121 $this->assertCount(0, $result['warnings']); 2122 $this->assertFalse(isset($result['gradingsummary'])); 2123 $this->assertFalse(isset($result['feedback'])); 2124 $this->assertFalse(isset($result['previousattempts'])); 2125 2126 $this->assertTrue($result['lastattempt']['submissionsenabled']); 2127 $this->assertFalse($result['lastattempt']['canedit']); 2128 $this->assertFalse($result['lastattempt']['cansubmit']); 2129 $this->assertFalse($result['lastattempt']['locked']); 2130 $this->assertFalse($result['lastattempt']['graded']); 2131 $this->assertEmpty($result['lastattempt']['extensionduedate']); 2132 $this->assertFalse($result['lastattempt']['blindmarking']); 2133 $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']); 2134 $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']); 2135 2136 } 2137 2138 /** 2139 * Test get_submission_status using the teacher role. 2140 */ 2141 public function test_get_submission_status_in_submission_status_for_teacher() { 2142 $this->resetAfterTest(true); 2143 2144 list($assign, $instance, $student1, $student2, $teacher, $g1, $g2) = $this->create_submission_for_testing_status(true); 2145 2146 // Now, as teacher, see the grading summary. 2147 $this->setUser($teacher); 2148 // First one group. 2149 $result = mod_assign_external::get_submission_status($assign->get_instance()->id, 0, $g1->id); 2150 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request. 2151 $this->assertDebuggingCalled(); 2152 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2153 2154 $this->assertCount(0, $result['warnings']); 2155 $this->assertFalse(isset($result['lastattempt'])); 2156 $this->assertFalse(isset($result['feedback'])); 2157 $this->assertFalse(isset($result['previousattempts'])); 2158 2159 $this->assertEquals(1, $result['gradingsummary']['participantcount']); 2160 $this->assertEquals(0, $result['gradingsummary']['submissiondraftscount']); 2161 $this->assertEquals(1, $result['gradingsummary']['submissionsenabled']); 2162 $this->assertEquals(0, $result['gradingsummary']['submissiondraftscount']); 2163 $this->assertEquals(1, $result['gradingsummary']['submissionssubmittedcount']); // One student from G1 submitted. 2164 $this->assertEquals(1, $result['gradingsummary']['submissionsneedgradingcount']); // One student from G1 submitted. 2165 $this->assertEmpty($result['gradingsummary']['warnofungroupedusers']); 2166 2167 // Second group. 2168 $result = mod_assign_external::get_submission_status($assign->get_instance()->id, 0, $g2->id); 2169 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2170 $this->assertCount(0, $result['warnings']); 2171 $this->assertEquals(1, $result['gradingsummary']['participantcount']); 2172 $this->assertEquals(0, $result['gradingsummary']['submissionssubmittedcount']); // G2 students didn't submit yet. 2173 $this->assertEquals(0, $result['gradingsummary']['submissionsneedgradingcount']); // G2 students didn't submit yet. 2174 2175 // Should return also 1 participant if we allow the function to auto-select the group. 2176 $result = mod_assign_external::get_submission_status($assign->get_instance()->id); 2177 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2178 $this->assertCount(0, $result['warnings']); 2179 $this->assertEquals(1, $result['gradingsummary']['participantcount']); 2180 $this->assertEquals(0, $result['gradingsummary']['submissiondraftscount']); 2181 $this->assertEquals(1, $result['gradingsummary']['submissionssubmittedcount']); // One student from G1 submitted. 2182 $this->assertEquals(1, $result['gradingsummary']['submissionsneedgradingcount']); // One student from G1 submitted. 2183 2184 // Now check draft submissions. 2185 list($assign, $instance, $student1, $student2, $teacher, $g1, $g2) = $this->create_submission_for_testing_status(false); 2186 $this->setUser($teacher); 2187 $result = mod_assign_external::get_submission_status($assign->get_instance()->id, 0, $g1->id); 2188 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2189 $this->assertCount(0, $result['warnings']); 2190 $this->assertEquals(1, $result['gradingsummary']['participantcount']); 2191 $this->assertEquals(1, $result['gradingsummary']['submissiondraftscount']); // We have a draft submission. 2192 $this->assertEquals(0, $result['gradingsummary']['submissionssubmittedcount']); // We have only draft submissions. 2193 $this->assertEquals(0, $result['gradingsummary']['submissionsneedgradingcount']); // We have only draft submissions. 2194 } 2195 2196 /** 2197 * Test get_submission_status for a reopened submission. 2198 */ 2199 public function test_get_submission_status_in_reopened_status() { 2200 global $USER; 2201 2202 $this->resetAfterTest(true); 2203 2204 list($assign, $instance, $student1, $student2, $teacher, $g1, $g2) = $this->create_submission_for_testing_status(true); 2205 $studentsubmission = $assign->get_user_submission($student1->id, true); 2206 2207 $this->setUser($teacher); 2208 // Grade and reopen. 2209 $feedbackpluginparams = array(); 2210 $feedbackpluginparams['files_filemanager'] = file_get_unused_draft_itemid(); 2211 $feedbackeditorparams = array('text' => 'Yeeha!', 2212 'format' => 1); 2213 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams; 2214 $result = mod_assign_external::save_grade($instance->id, 2215 $student1->id, 2216 50.0, 2217 -1, 2218 false, 2219 'released', 2220 false, 2221 $feedbackpluginparams); 2222 $USER->ignoresesskey = true; 2223 $assign->testable_process_add_attempt($student1->id); 2224 2225 $this->setUser($student1); 2226 2227 $result = mod_assign_external::get_submission_status($assign->get_instance()->id); 2228 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request. 2229 $this->assertDebuggingCalled(); 2230 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2231 2232 $this->assertCount(0, $result['warnings']); 2233 $this->assertFalse(isset($result['gradingsummary'])); 2234 2235 $this->assertTrue($result['lastattempt']['submissionsenabled']); 2236 $this->assertTrue($result['lastattempt']['canedit']); 2237 $this->assertFalse($result['lastattempt']['cansubmit']); 2238 $this->assertFalse($result['lastattempt']['locked']); 2239 $this->assertFalse($result['lastattempt']['graded']); 2240 $this->assertEmpty($result['lastattempt']['extensionduedate']); 2241 $this->assertFalse($result['lastattempt']['blindmarking']); 2242 $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']); 2243 $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']); 2244 2245 // Check new attempt reopened. 2246 $this->assertEquals($student1->id, $result['lastattempt']['submission']['userid']); 2247 $this->assertEquals(1, $result['lastattempt']['submission']['attemptnumber']); 2248 $this->assertEquals('reopened', $result['lastattempt']['submission']['status']); 2249 $this->assertEquals(0, $result['lastattempt']['submission']['groupid']); 2250 $this->assertEquals($assign->get_instance()->id, $result['lastattempt']['submission']['assignment']); 2251 $this->assertEquals(1, $result['lastattempt']['submission']['latest']); 2252 $this->assertCount(3, $result['lastattempt']['submission']['plugins']); 2253 2254 // Now see feedback and the attempts history (remember, is a submission reopened). 2255 // Only 2 fields (no grade, no plugins data). 2256 $this->assertCount(2, $result['feedback']); 2257 2258 // One previous attempt. 2259 $this->assertCount(1, $result['previousattempts']); 2260 $this->assertEquals(0, $result['previousattempts'][0]['attemptnumber']); 2261 $this->assertEquals(50, $result['previousattempts'][0]['grade']['grade']); 2262 $this->assertEquals($teacher->id, $result['previousattempts'][0]['grade']['grader']); 2263 $this->assertEquals($student1->id, $result['previousattempts'][0]['grade']['userid']); 2264 2265 // Map plugins based on their type - we can't rely on them being in a 2266 // particular order, especially if 3rd party plugins are installed. 2267 $feedbackplugins = array(); 2268 foreach ($result['previousattempts'][0]['feedbackplugins'] as $plugin) { 2269 $feedbackplugins[$plugin['type']] = $plugin; 2270 } 2271 $this->assertEquals('Yeeha!', $feedbackplugins['comments']['editorfields'][0]['text']); 2272 2273 $submissionplugins = array(); 2274 foreach ($result['previousattempts'][0]['submission']['plugins'] as $plugin) { 2275 $submissionplugins[$plugin['type']] = $plugin; 2276 } 2277 // Format expected online text. 2278 $onlinetext = 'Submission text with a <a href="@@PLUGINFILE@@/intro.txt">link</a>'; 2279 list($expectedtext, $expectedformat) = external_format_text($onlinetext, FORMAT_HTML, $assign->get_context()->id, 2280 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $studentsubmission->id); 2281 2282 $this->assertEquals($expectedtext, $submissionplugins['onlinetext']['editorfields'][0]['text']); 2283 $this->assertEquals($expectedformat, $submissionplugins['onlinetext']['editorfields'][0]['format']); 2284 $this->assertEquals('/', $submissionplugins['file']['fileareas'][0]['files'][0]['filepath']); 2285 $this->assertEquals('t.txt', $submissionplugins['file']['fileareas'][0]['files'][0]['filename']); 2286 2287 } 2288 2289 /** 2290 * Test access control for get_submission_status. 2291 * 2292 * @expectedException required_capability_exception 2293 */ 2294 public function test_get_submission_status_access_control() { 2295 $this->resetAfterTest(true); 2296 2297 list($assign, $instance, $student1, $student2, $teacher, $g1, $g2) = $this->create_submission_for_testing_status(); 2298 2299 $this->setUser($student2); 2300 2301 // Access control test. 2302 mod_assign_external::get_submission_status($assign->get_instance()->id, $student1->id); 2303 2304 } 2305 2306 /** 2307 * Test hidden grader for get_submission_status. 2308 */ 2309 public function test_get_submission_status_hidden_grader() { 2310 $this->resetAfterTest(true); 2311 2312 list($assign, $instance, $student1, $student2, $teacher, $g1, $g2) = $this->create_submission_for_testing_status(true); 2313 2314 // Grade the assign for the student1. 2315 $this->setUser($teacher); 2316 2317 $data = new stdClass(); 2318 $data->grade = '50.0'; 2319 $data->assignfeedbackcomments_editor = ['text' => '']; 2320 $assign->testable_apply_grade_to_user($data, $student1->id, 0); 2321 2322 $this->setUser($student1); 2323 2324 // Check that the student can see the grader by default. 2325 $result = mod_assign_external::get_submission_status($assign->get_instance()->id); 2326 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request. 2327 $this->assertDebuggingCalled(); 2328 2329 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2330 2331 $this->assertTrue(isset($result['feedback'])); 2332 $this->assertTrue(isset($result['feedback']['grade'])); 2333 $this->assertEquals($teacher->id, $result['feedback']['grade']['grader']); 2334 2335 // Now change the setting so the grader is hidden. 2336 $this->setAdminUser(); 2337 2338 $instance = $assign->get_instance(); 2339 $instance->instance = $instance->id; 2340 $instance->hidegrader = true; 2341 $assign->update_instance($instance); 2342 2343 $this->setUser($student1); 2344 2345 // Check that the student cannot see the grader anymore. 2346 $result = mod_assign_external::get_submission_status($assign->get_instance()->id); 2347 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2348 2349 $this->assertTrue(isset($result['feedback'])); 2350 $this->assertTrue(isset($result['feedback']['grade'])); 2351 $this->assertEquals(-1, $result['feedback']['grade']['grader']); 2352 2353 // Check that the teacher can see the grader. 2354 $this->setUser($teacher); 2355 2356 $result = mod_assign_external::get_submission_status($assign->get_instance()->id, $student1->id); 2357 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2358 2359 $this->assertTrue(isset($result['feedback'])); 2360 $this->assertTrue(isset($result['feedback']['grade'])); 2361 $this->assertEquals($teacher->id, $result['feedback']['grade']['grader']); 2362 } 2363 2364 /** 2365 * Test get_submission_status with override for student. 2366 */ 2367 public function test_get_submission_status_with_override() { 2368 global $DB; 2369 2370 $this->resetAfterTest(true); 2371 2372 list($assign, $instance, $student1, $student2, $teacher, $g1, $g2) = $this->create_submission_for_testing_status(); 2373 2374 $overridedata = new \stdClass(); 2375 $overridedata->assignid = $assign->get_instance()->id; 2376 $overridedata->userid = $student1->id; 2377 $overridedata->allowsubmissionsfromdate = time() + YEARSECS; 2378 $DB->insert_record('assign_overrides', $overridedata); 2379 2380 $result = mod_assign_external::get_submission_status($assign->get_instance()->id); 2381 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request. 2382 $this->assertDebuggingCalled(); 2383 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2384 2385 $this->assertCount(0, $result['warnings']); 2386 $this->assertFalse(isset($result['gradingsummary'])); 2387 $this->assertFalse(isset($result['feedback'])); 2388 $this->assertFalse(isset($result['previousattempts'])); 2389 2390 $this->assertTrue($result['lastattempt']['submissionsenabled']); 2391 $this->assertFalse($result['lastattempt']['canedit']); // False because of override. 2392 $this->assertFalse($result['lastattempt']['cansubmit']); 2393 $this->assertFalse($result['lastattempt']['locked']); 2394 $this->assertFalse($result['lastattempt']['graded']); 2395 $this->assertEmpty($result['lastattempt']['extensionduedate']); 2396 $this->assertFalse($result['lastattempt']['blindmarking']); 2397 $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']); 2398 $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']); 2399 2400 // Same assignment but user without override. 2401 $this->setUser($student2); 2402 2403 $result = mod_assign_external::get_submission_status($assign->get_instance()->id); 2404 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result); 2405 2406 // The submission is now in draft mode. 2407 $this->assertCount(0, $result['warnings']); 2408 $this->assertFalse(isset($result['gradingsummary'])); 2409 $this->assertFalse(isset($result['feedback'])); 2410 $this->assertFalse(isset($result['previousattempts'])); 2411 2412 $this->assertTrue($result['lastattempt']['submissionsenabled']); 2413 $this->assertTrue($result['lastattempt']['canedit']); // True because there is not override for this user. 2414 $this->assertFalse($result['lastattempt']['cansubmit']); 2415 $this->assertFalse($result['lastattempt']['locked']); 2416 $this->assertFalse($result['lastattempt']['graded']); 2417 $this->assertEmpty($result['lastattempt']['extensionduedate']); 2418 $this->assertFalse($result['lastattempt']['blindmarking']); 2419 $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']); 2420 $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']); 2421 } 2422 2423 /** 2424 * get_participant should throw an excaption if the requested assignment doesn't exist. 2425 * 2426 * @expectedException moodle_exception 2427 */ 2428 public function test_get_participant_no_assignment() { 2429 $this->resetAfterTest(true); 2430 mod_assign_external::get_participant('-1', '-1', false); 2431 } 2432 2433 /** 2434 * get_participant should throw a require_login_exception if the user doesn't have access 2435 * to view assignments. 2436 * 2437 * @expectedException require_login_exception 2438 */ 2439 public function test_get_participant_no_view_capability() { 2440 global $DB; 2441 $this->resetAfterTest(true); 2442 2443 $result = $this->create_assign_with_student_and_teacher(); 2444 $assign = $result['assign']; 2445 $student = $result['student']; 2446 $course = $result['course']; 2447 $context = context_course::instance($course->id); 2448 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 2449 2450 $this->setUser($student); 2451 assign_capability('mod/assign:view', CAP_PROHIBIT, $studentrole->id, $context->id, true); 2452 2453 mod_assign_external::get_participant($assign->id, $student->id, false); 2454 } 2455 2456 /** 2457 * get_participant should throw a required_capability_exception if the user doesn't have access 2458 * to view assignment grades. 2459 * 2460 * @expectedException required_capability_exception 2461 */ 2462 public function test_get_participant_no_grade_capability() { 2463 global $DB; 2464 $this->resetAfterTest(true); 2465 2466 $result = $this->create_assign_with_student_and_teacher(); 2467 $assign = $result['assign']; 2468 $student = $result['student']; 2469 $teacher = $result['teacher']; 2470 $course = $result['course']; 2471 $context = context_course::instance($course->id); 2472 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 2473 2474 $this->setUser($teacher); 2475 assign_capability('mod/assign:viewgrades', CAP_PROHIBIT, $teacherrole->id, $context->id, true); 2476 assign_capability('mod/assign:grade', CAP_PROHIBIT, $teacherrole->id, $context->id, true); 2477 accesslib_clear_all_caches_for_unit_testing(); 2478 2479 mod_assign_external::get_participant($assign->id, $student->id, false); 2480 } 2481 2482 /** 2483 * get_participant should throw an exception if the user isn't enrolled in the course. 2484 * 2485 * @expectedException moodle_exception 2486 */ 2487 public function test_get_participant_no_participant() { 2488 global $DB; 2489 $this->resetAfterTest(true); 2490 2491 $result = $this->create_assign_with_student_and_teacher(array('blindmarking' => true)); 2492 $student = $this->getDataGenerator()->create_user(); 2493 $assign = $result['assign']; 2494 $teacher = $result['teacher']; 2495 2496 $this->setUser($teacher); 2497 2498 $result = mod_assign_external::get_participant($assign->id, $student->id, false); 2499 $result = external_api::clean_returnvalue(mod_assign_external::get_participant_returns(), $result); 2500 } 2501 2502 /** 2503 * get_participant should return a summarised list of details with a different fullname if blind 2504 * marking is on for the requested assignment. 2505 */ 2506 public function test_get_participant_blind_marking() { 2507 global $DB; 2508 $this->resetAfterTest(true); 2509 2510 $result = $this->create_assign_with_student_and_teacher(array('blindmarking' => true)); 2511 $assign = $result['assign']; 2512 $student = $result['student']; 2513 $teacher = $result['teacher']; 2514 $course = $result['course']; 2515 $context = context_course::instance($course->id); 2516 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 2517 2518 $this->setUser($teacher); 2519 2520 $result = mod_assign_external::get_participant($assign->id, $student->id, true); 2521 $result = external_api::clean_returnvalue(mod_assign_external::get_participant_returns(), $result); 2522 $this->assertEquals($student->id, $result['id']); 2523 $this->assertFalse(fullname($student) == $result['fullname']); 2524 $this->assertFalse($result['submitted']); 2525 $this->assertFalse($result['requiregrading']); 2526 $this->assertFalse($result['grantedextension']); 2527 $this->assertTrue($result['blindmarking']); 2528 // Make sure we don't get any additional info. 2529 $this->assertArrayNotHasKey('user', $result); 2530 } 2531 2532 /** 2533 * get_participant should return a summarised list of details if requested. 2534 */ 2535 public function test_get_participant_no_user() { 2536 global $DB; 2537 $this->resetAfterTest(true); 2538 2539 $result = $this->create_assign_with_student_and_teacher(); 2540 $assignmodule = $result['assign']; 2541 $student = $result['student']; 2542 $teacher = $result['teacher']; 2543 $course = $result['course']; 2544 $context = context_course::instance($course->id); 2545 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 2546 2547 // Create an assign instance to save a submission. 2548 set_config('submissionreceipts', 0, 'assign'); 2549 2550 $cm = get_coursemodule_from_instance('assign', $assignmodule->id); 2551 $context = context_module::instance($cm->id); 2552 2553 $assign = new assign($context, $cm, $course); 2554 2555 $this->setUser($student); 2556 2557 // Simulate a submission. 2558 $data = new stdClass(); 2559 $data->onlinetext_editor = array( 2560 'itemid' => file_get_unused_draft_itemid(), 2561 'text' => 'Student submission text', 2562 'format' => FORMAT_MOODLE 2563 ); 2564 2565 $notices = array(); 2566 $assign->save_submission($data, $notices); 2567 2568 $data = new stdClass; 2569 $data->userid = $student->id; 2570 $assign->submit_for_grading($data, array()); 2571 2572 $this->setUser($teacher); 2573 2574 $result = mod_assign_external::get_participant($assignmodule->id, $student->id, false); 2575 $result = external_api::clean_returnvalue(mod_assign_external::get_participant_returns(), $result); 2576 $this->assertEquals($student->id, $result['id']); 2577 $this->assertEquals(fullname($student), $result['fullname']); 2578 $this->assertTrue($result['submitted']); 2579 $this->assertTrue($result['requiregrading']); 2580 $this->assertFalse($result['grantedextension']); 2581 $this->assertFalse($result['blindmarking']); 2582 // Make sure we don't get any additional info. 2583 $this->assertArrayNotHasKey('user', $result); 2584 } 2585 2586 /** 2587 * get_participant should return user details if requested. 2588 */ 2589 public function test_get_participant_full_details() { 2590 global $DB; 2591 $this->resetAfterTest(true); 2592 2593 $result = $this->create_assign_with_student_and_teacher(); 2594 $assign = $result['assign']; 2595 $student = $result['student']; 2596 $teacher = $result['teacher']; 2597 $course = $result['course']; 2598 $context = context_course::instance($course->id); 2599 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 2600 2601 $this->setUser($teacher); 2602 2603 $result = mod_assign_external::get_participant($assign->id, $student->id, true); 2604 $result = external_api::clean_returnvalue(mod_assign_external::get_participant_returns(), $result); 2605 // Check some of the extended properties we get when requesting the user. 2606 $this->assertEquals($student->id, $result['id']); 2607 // We should get user infomation back. 2608 $user = $result['user']; 2609 $this->assertFalse(empty($user)); 2610 $this->assertEquals($student->firstname, $user['firstname']); 2611 $this->assertEquals($student->lastname, $user['lastname']); 2612 $this->assertEquals($student->email, $user['email']); 2613 } 2614 2615 /** 2616 * get_participant should return group details if a group submission was 2617 * submitted. 2618 */ 2619 public function test_get_participant_group_submission() { 2620 global $DB; 2621 2622 $this->resetAfterTest(true); 2623 2624 $result = $this->create_assign_with_student_and_teacher(array( 2625 'assignsubmission_onlinetext_enabled' => 1, 2626 'teamsubmission' => 1 2627 )); 2628 $assignmodule = $result['assign']; 2629 $student = $result['student']; 2630 $teacher = $result['teacher']; 2631 $course = $result['course']; 2632 $context = context_course::instance($course->id); 2633 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 2634 $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 2635 $cm = get_coursemodule_from_instance('assign', $assignmodule->id); 2636 $context = context_module::instance($cm->id); 2637 $assign = new mod_assign_testable_assign($context, $cm, $course); 2638 2639 groups_add_member($group, $student); 2640 2641 $this->setUser($student); 2642 $submission = $assign->get_group_submission($student->id, $group->id, true); 2643 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED; 2644 $assign->testable_update_submission($submission, $student->id, true, false); 2645 $data = new stdClass(); 2646 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(), 2647 'text' => 'Submission text', 2648 'format' => FORMAT_MOODLE); 2649 $plugin = $assign->get_submission_plugin_by_type('onlinetext'); 2650 $plugin->save($submission, $data); 2651 2652 $this->setUser($teacher); 2653 2654 $result = mod_assign_external::get_participant($assignmodule->id, $student->id, false); 2655 $result = external_api::clean_returnvalue(mod_assign_external::get_participant_returns(), $result); 2656 // Check some of the extended properties we get when not requesting a summary. 2657 $this->assertEquals($student->id, $result['id']); 2658 $this->assertEquals($group->id, $result['groupid']); 2659 $this->assertEquals($group->name, $result['groupname']); 2660 } 2661 2662 /** 2663 * Test get_participant() when relative dates mode is enabled on the course. 2664 * 2665 * @dataProvider get_participant_relative_dates_provider 2666 * @param array $courseconfig the config to use when creating the course. 2667 * @param array $assignconfig the config to use when creating the assignment. 2668 * @param array $enrolconfig the enrolement to create. 2669 * @param array $expectedproperties array of expected assign properties. 2670 */ 2671 public function test_get_participant_relative_dates(array $courseconfig, array $assignconfig, array $enrolconfig, 2672 array $expectedproperties) { 2673 $this->resetAfterTest(); 2674 2675 set_config('enablecourserelativedates', true); // Enable relative dates at site level. 2676 2677 $course = $this->getDataGenerator()->create_course($courseconfig); 2678 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 2679 $assignconfig['course'] = $course->id; 2680 $instance = $generator->create_instance($assignconfig); 2681 $cm = get_coursemodule_from_instance('assign', $instance->id); 2682 $context = context_module::instance($cm->id); 2683 $assign = new assign($context, $cm, $course); 2684 2685 $user = $this->getDataGenerator()->create_and_enrol($course, ...array_values($enrolconfig)); 2686 2687 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher', null, 'manual', time() - 50 * DAYSECS); 2688 2689 $this->setUser($teacher); 2690 $result = mod_assign_external::get_participant($assign->get_instance()->id, $user->id, false); 2691 $result = external_api::clean_returnvalue(mod_assign_external::get_participant_returns(), $result); 2692 2693 foreach ($expectedproperties as $propertyname => $propertyval) { 2694 $this->assertEquals($propertyval, $result[$propertyname]); 2695 } 2696 } 2697 2698 /** 2699 * The test_get_participant_relative_dates data provider. 2700 */ 2701 public function get_participant_relative_dates_provider() { 2702 $timenow = time(); 2703 2704 return [ 2705 'Student whose enrolment starts after the course start date, relative dates mode enabled' => [ 2706 'courseconfig' => ['relativedatesmode' => true, 'startdate' => $timenow - 10 * DAYSECS], 2707 'assignconfig' => ['duedate' => $timenow + 4 * DAYSECS], 2708 'enrolconfig' => ['shortname' => 'student', 'userparams' => null, 'method' => 'manual', 2709 'startdate' => $timenow - 8 * DAYSECS], 2710 'expectedproperties' => ['duedate' => $timenow + 6 * DAYSECS] 2711 ], 2712 'Student whose enrolment starts before the course start date, relative dates mode enabled' => [ 2713 'courseconfig' => ['relativedatesmode' => true, 'startdate' => $timenow - 10 * DAYSECS], 2714 'assignconfig' => ['duedate' => $timenow + 4 * DAYSECS], 2715 'enrolconfig' => ['shortname' => 'student', 'userparams' => null, 'method' => 'manual', 2716 'startdate' => $timenow - 12 * DAYSECS], 2717 'expectedproperties' => ['duedate' => $timenow + 4 * DAYSECS] 2718 ], 2719 ]; 2720 } 2721 2722 /** 2723 * Test for mod_assign_external::list_participants(). 2724 * 2725 * @throws coding_exception 2726 */ 2727 public function test_list_participants_user_info_with_special_characters() { 2728 global $CFG, $DB; 2729 $this->resetAfterTest(true); 2730 $CFG->showuseridentity = 'idnumber,email,phone1,phone2,department,institution'; 2731 2732 $data = $this->create_assign_with_student_and_teacher(); 2733 $assignment = $data['assign']; 2734 $teacher = $data['teacher']; 2735 2736 // Set data for student info that contain special characters. 2737 $student = $data['student']; 2738 $student->idnumber = '<\'"1am@wesome&c00l"\'>'; 2739 $student->phone1 = '+63 (999) 888-7777'; 2740 $student->phone2 = '(011) [15]4-123-4567'; 2741 $student->department = 'Arts & Sciences & \' " Ā¢ Ā£ Ā© ā¬ Ā„ Ā® < >'; 2742 $student->institution = 'University of Awesome People & \' " Ā¢ Ā£ Ā© ā¬ Ā„ Ā® < >'; 2743 // Assert that we have valid user data. 2744 $this->assertTrue(core_user::validate($student)); 2745 // Update the user record. 2746 $DB->update_record('user', $student); 2747 2748 $this->setUser($teacher); 2749 $participants = mod_assign_external::list_participants($assignment->id, 0, '', 0, 0, false, true, true); 2750 $participants = external_api::clean_returnvalue(mod_assign_external::list_participants_returns(), $participants); 2751 $this->assertCount(1, $participants); 2752 2753 // Asser that we have a valid response data. 2754 $response = external_api::clean_returnvalue(mod_assign_external::list_participants_returns(), $participants); 2755 $this->assertEquals($response, $participants); 2756 2757 // Check participant data. 2758 $participant = $participants[0]; 2759 $this->assertEquals($student->idnumber, $participant['idnumber']); 2760 $this->assertEquals($student->email, $participant['email']); 2761 $this->assertEquals($student->phone1, $participant['phone1']); 2762 $this->assertEquals($student->phone2, $participant['phone2']); 2763 $this->assertEquals($student->department, $participant['department']); 2764 $this->assertEquals($student->institution, $participant['institution']); 2765 $this->assertArrayHasKey('enrolledcourses', $participant); 2766 2767 $participants = mod_assign_external::list_participants($assignment->id, 0, '', 0, 0, false, false, true); 2768 $participants = external_api::clean_returnvalue(mod_assign_external::list_participants_returns(), $participants); 2769 // Check that the list of courses the participant is enrolled is not returned. 2770 $participant = $participants[0]; 2771 $this->assertArrayNotHasKey('enrolledcourses', $participant); 2772 } 2773 2774 /** 2775 * Test for the type of the user-related properties in mod_assign_external::list_participants_returns(). 2776 */ 2777 public function test_list_participants_returns_user_property_types() { 2778 // Get user properties. 2779 $userdesc = core_user_external::user_description(); 2780 $this->assertTrue(isset($userdesc->keys)); 2781 $userproperties = array_keys($userdesc->keys); 2782 2783 // Get returns description for mod_assign_external::list_participants_returns(). 2784 $listreturns = mod_assign_external::list_participants_returns(); 2785 $this->assertTrue(isset($listreturns->content)); 2786 $listreturnsdesc = $listreturns->content->keys; 2787 2788 // Iterate over list returns description's keys. 2789 foreach ($listreturnsdesc as $key => $desc) { 2790 // Check if key exists in user properties and the description has a type attribute. 2791 if (in_array($key, $userproperties) && isset($desc->type)) { 2792 try { 2793 // The core_user::get_property_type() method might throw a coding_exception since 2794 // core_user_external::user_description() might contain properties that are not yet included in 2795 // core_user's $propertiescache. 2796 $propertytype = core_user::get_property_type($key); 2797 2798 // Assert that user-related property types match those of the defined in core_user. 2799 $this->assertEquals($propertytype, $desc->type); 2800 } catch (coding_exception $e) { 2801 // All good. 2802 } 2803 } 2804 } 2805 } 2806 2807 /** 2808 * Create a a course, assignment module instance, student and teacher and enrol them in 2809 * the course. 2810 * 2811 * @param array $params parameters to be provided to the assignment module creation 2812 * @return array containing the course, assignment module, student and teacher 2813 */ 2814 private function create_assign_with_student_and_teacher($params = array()) { 2815 global $DB; 2816 2817 $course = $this->getDataGenerator()->create_course(); 2818 $params = array_merge(array( 2819 'course' => $course->id, 2820 'name' => 'assignment', 2821 'intro' => 'assignment intro text', 2822 ), $params); 2823 2824 // Create a course and assignment and users. 2825 $assign = $this->getDataGenerator()->create_module('assign', $params); 2826 2827 $cm = get_coursemodule_from_instance('assign', $assign->id); 2828 $context = context_module::instance($cm->id); 2829 2830 $student = $this->getDataGenerator()->create_user(); 2831 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 2832 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id); 2833 $teacher = $this->getDataGenerator()->create_user(); 2834 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 2835 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id); 2836 2837 assign_capability('mod/assign:view', CAP_ALLOW, $teacherrole->id, $context->id, true); 2838 assign_capability('mod/assign:viewgrades', CAP_ALLOW, $teacherrole->id, $context->id, true); 2839 assign_capability('mod/assign:grade', CAP_ALLOW, $teacherrole->id, $context->id, true); 2840 accesslib_clear_all_caches_for_unit_testing(); 2841 2842 return array( 2843 'course' => $course, 2844 'assign' => $assign, 2845 'student' => $student, 2846 'teacher' => $teacher 2847 ); 2848 } 2849 2850 /** 2851 * Test test_view_assign 2852 */ 2853 public function test_view_assign() { 2854 global $CFG; 2855 2856 $CFG->enablecompletion = 1; 2857 $this->resetAfterTest(); 2858 2859 $this->setAdminUser(); 2860 // Setup test data. 2861 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 2862 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id), 2863 array('completion' => 2, 'completionview' => 1)); 2864 $context = context_module::instance($assign->cmid); 2865 $cm = get_coursemodule_from_instance('assign', $assign->id); 2866 2867 $result = mod_assign_external::view_assign($assign->id); 2868 $result = external_api::clean_returnvalue(mod_assign_external::view_assign_returns(), $result); 2869 $this->assertTrue($result['status']); 2870 $this->assertEmpty($result['warnings']); 2871 2872 // Check completion status. 2873 $completion = new completion_info($course); 2874 $completiondata = $completion->get_data($cm); 2875 $this->assertEquals(1, $completiondata->completionstate); 2876 } 2877 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body