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