on-demand release 3.1beta+
[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',
156 'fullname' => 'Lightwork Course 1',
157 'summary' => 'Lightwork Course 1 description',
158 'summaryformat' => FORMAT_MOODLE,
159 'category' => $category->id
160 ));
161
162 // Create a second course, just for testing.
163 $course2 = self::getDataGenerator()->create_course(array(
164 'idnumber' => 'idnumbercourse2',
165 'fullname' => 'Lightwork Course 2',
166 'summary' => 'Lightwork Course 2 description',
167 'summaryformat' => FORMAT_MOODLE,
168 'category' => $category->id
169 ));
170
988065c0 171 // Create the assignment module with links to a filerecord.
1378838e
PC
172 $assign1 = self::getDataGenerator()->create_module('assign', array(
173 'course' => $course1->id,
d1ec5c83 174 'name' => 'lightwork assignment',
988065c0
PFO
175 'intro' => 'the assignment intro text here <a href="@@PLUGINFILE@@/intro.txt">link</a>',
176 'introformat' => FORMAT_HTML,
d1ec5c83
PC
177 'markingworkflow' => 1,
178 'markingallocation' => 1
1378838e
PC
179 ));
180
988065c0
PFO
181 // Add a file as assignment attachment.
182 $context = context_module::instance($assign1->cmid);
183 $filerecord = array('component' => 'mod_assign', 'filearea' => 'intro', 'contextid' => $context->id, 'itemid' => 0,
184 'filename' => 'intro.txt', 'filepath' => '/');
185 $fs = get_file_storage();
186 $fs->create_file_from_string($filerecord, 'Test intro file');
187
1378838e
PC
188 // Create manual enrolment record.
189 $enrolid = $DB->insert_record('enrol', (object)array(
190 'enrol' => 'manual',
191 'status' => 0,
192 'courseid' => $course1->id
193 ));
194
195 // Create the user and give them capabilities.
196 $context = context_course::instance($course1->id);
197 $roleid = $this->assignUserCapability('moodle/course:view', $context->id);
74b63eae 198 $context = context_module::instance($assign1->cmid);
1378838e
PC
199 $this->assignUserCapability('mod/assign:view', $context->id, $roleid);
200
201 // Create the user enrolment record.
202 $DB->insert_record('user_enrolments', (object)array(
203 'status' => 0,
204 'enrolid' => $enrolid,
205 'userid' => $USER->id
206 ));
207
0be81772
JL
208 // Add a file as assignment attachment.
209 $filerecord = array('component' => 'mod_assign', 'filearea' => ASSIGN_INTROATTACHMENT_FILEAREA,
210 'contextid' => $context->id, 'itemid' => 0,
211 'filename' => 'introattachment.txt', 'filepath' => '/');
212 $fs = get_file_storage();
213 $fs->create_file_from_string($filerecord, 'Test intro attachment file');
214
1378838e 215 $result = mod_assign_external::get_assignments();
fb695f6e
JM
216
217 // We need to execute the return values cleaning process to simulate the web service server.
218 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
219
1378838e
PC
220 // Check the course and assignment are returned.
221 $this->assertEquals(1, count($result['courses']));
222 $course = $result['courses'][0];
223 $this->assertEquals('Lightwork Course 1', $course['fullname']);
224 $this->assertEquals(1, count($course['assignments']));
225 $assignment = $course['assignments'][0];
226 $this->assertEquals($assign1->id, $assignment['id']);
227 $this->assertEquals($course1->id, $assignment['course']);
228 $this->assertEquals('lightwork assignment', $assignment['name']);
988065c0
PFO
229 $this->assertContains('the assignment intro text here', $assignment['intro']);
230 // Check the url of the file attatched.
9e6c63a7 231 $this->assertRegExp('@"' . $CFG->wwwroot . '/webservice/pluginfile.php/\d+/mod_assign/intro/intro\.txt"@', $assignment['intro']);
d1ec5c83
PC
232 $this->assertEquals(1, $assignment['markingworkflow']);
233 $this->assertEquals(1, $assignment['markingallocation']);
1378838e 234
0be81772
JL
235 $this->assertCount(1, $assignment['introattachments']);
236 $this->assertEquals('introattachment.txt', $assignment['introattachments'][0]['filename']);
237
238 // Now, hide the descritption until the submission from date.
239 $DB->set_field('assign', 'alwaysshowdescription', 0, array('id' => $assign1->id));
240 $DB->set_field('assign', 'allowsubmissionsfromdate', time() + DAYSECS, array('id' => $assign1->id));
241
1378838e 242 $result = mod_assign_external::get_assignments(array($course1->id));
fb695f6e
JM
243
244 // We need to execute the return values cleaning process to simulate the web service server.
245 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
246
1378838e
PC
247 $this->assertEquals(1, count($result['courses']));
248 $course = $result['courses'][0];
249 $this->assertEquals('Lightwork Course 1', $course['fullname']);
250 $this->assertEquals(1, count($course['assignments']));
251 $assignment = $course['assignments'][0];
252 $this->assertEquals($assign1->id, $assignment['id']);
253 $this->assertEquals($course1->id, $assignment['course']);
254 $this->assertEquals('lightwork assignment', $assignment['name']);
0be81772
JL
255 $this->assertArrayNotHasKey('intro', $assignment);
256 $this->assertArrayNotHasKey('introattachments', $assignment);
d1ec5c83
PC
257 $this->assertEquals(1, $assignment['markingworkflow']);
258 $this->assertEquals(1, $assignment['markingallocation']);
1378838e
PC
259
260 $result = mod_assign_external::get_assignments(array($course2->id));
fb695f6e
JM
261
262 // We need to execute the return values cleaning process to simulate the web service server.
263 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
264
1378838e
PC
265 $this->assertEquals(0, count($result['courses']));
266 $this->assertEquals(1, count($result['warnings']));
8e76a2fa
JL
267
268 // Test with non-enrolled user, but with view capabilities.
269 $this->setAdminUser();
270 $result = mod_assign_external::get_assignments();
271 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
272 $this->assertEquals(0, count($result['courses']));
273 $this->assertEquals(0, count($result['warnings']));
274
275 // Expect no courses, because we are not using the special flag.
276 $result = mod_assign_external::get_assignments(array($course1->id));
277 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
278 $this->assertCount(0, $result['courses']);
279
280 // Now use the special flag to return courses where you are not enroled in.
281 $result = mod_assign_external::get_assignments(array($course1->id), array(), true);
282 $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
283 $this->assertCount(1, $result['courses']);
284
285 $course = $result['courses'][0];
286 $this->assertEquals('Lightwork Course 1', $course['fullname']);
287 $this->assertEquals(1, count($course['assignments']));
288 $assignment = $course['assignments'][0];
289 $this->assertEquals($assign1->id, $assignment['id']);
290 $this->assertEquals($course1->id, $assignment['course']);
291 $this->assertEquals('lightwork assignment', $assignment['name']);
292 $this->assertArrayNotHasKey('intro', $assignment);
293 $this->assertArrayNotHasKey('introattachments', $assignment);
294 $this->assertEquals(1, $assignment['markingworkflow']);
295 $this->assertEquals(1, $assignment['markingallocation']);
1378838e 296 }
c144959c
PC
297
298 /**
299 * Test get_submissions
300 */
05a6445a 301 public function test_get_submissions() {
c144959c
PC
302 global $DB, $USER;
303
304 $this->resetAfterTest(true);
305 // Create a course and assignment.
306 $coursedata['idnumber'] = 'idnumbercourse1';
307 $coursedata['fullname'] = 'Lightwork Course 1';
308 $coursedata['summary'] = 'Lightwork Course 1 description';
309 $coursedata['summaryformat'] = FORMAT_MOODLE;
310 $course1 = self::getDataGenerator()->create_course($coursedata);
311
312 $assigndata['course'] = $course1->id;
313 $assigndata['name'] = 'lightwork assignment';
314
315 $assign1 = self::getDataGenerator()->create_module('assign', $assigndata);
316
317 // Create a student with an online text submission.
a13fbf5f 318 // First attempt.
c144959c
PC
319 $student = self::getDataGenerator()->create_user();
320 $submission = new stdClass();
321 $submission->assignment = $assign1->id;
322 $submission->userid = $student->id;
323 $submission->timecreated = time();
324 $submission->timemodified = $submission->timecreated;
a13fbf5f
DW
325 $submission->status = 'draft';
326 $submission->attemptnumber = 0;
1523f9e0 327 $submission->latest = 0;
a13fbf5f
DW
328 $sid = $DB->insert_record('assign_submission', $submission);
329
330 // Second attempt.
331 $submission = new stdClass();
332 $submission->assignment = $assign1->id;
333 $submission->userid = $student->id;
334 $submission->timecreated = time();
335 $submission->timemodified = $submission->timecreated;
c144959c 336 $submission->status = 'submitted';
a13fbf5f 337 $submission->attemptnumber = 1;
1523f9e0 338 $submission->latest = 1;
c144959c
PC
339 $sid = $DB->insert_record('assign_submission', $submission);
340 $submission->id = $sid;
341
342 $onlinetextsubmission = new stdClass();
9f780282 343 $onlinetextsubmission->onlinetext = "<p>online test text</p>";
c144959c
PC
344 $onlinetextsubmission->onlineformat = 1;
345 $onlinetextsubmission->submission = $submission->id;
346 $onlinetextsubmission->assignment = $assign1->id;
347 $DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission);
348
349 // Create manual enrolment record.
07df8c38
PC
350 $manualenroldata['enrol'] = 'manual';
351 $manualenroldata['status'] = 0;
352 $manualenroldata['courseid'] = $course1->id;
353 $enrolid = $DB->insert_record('enrol', $manualenroldata);
c144959c
PC
354
355 // Create a teacher and give them capabilities.
356 $context = context_course::instance($course1->id);
357 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
d2c58b95 358 $context = context_module::instance($assign1->cmid);
c144959c
PC
359 $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
360
361 // Create the teacher's enrolment record.
07df8c38
PC
362 $userenrolmentdata['status'] = 0;
363 $userenrolmentdata['enrolid'] = $enrolid;
364 $userenrolmentdata['userid'] = $USER->id;
365 $DB->insert_record('user_enrolments', $userenrolmentdata);
c144959c
PC
366
367 $assignmentids[] = $assign1->id;
368 $result = mod_assign_external::get_submissions($assignmentids);
7f45111e 369 $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result);
c144959c
PC
370
371 // Check the online text submission is returned.
372 $this->assertEquals(1, count($result['assignments']));
373 $assignment = $result['assignments'][0];
374 $this->assertEquals($assign1->id, $assignment['assignmentid']);
375 $this->assertEquals(1, count($assignment['submissions']));
376 $submission = $assignment['submissions'][0];
377 $this->assertEquals($sid, $submission['id']);
bdf1ac27 378 $this->assertCount(1, $submission['plugins']);
c144959c 379 }
07df8c38
PC
380
381 /**
382 * Test get_user_flags
383 */
05a6445a 384 public function test_get_user_flags() {
07df8c38
PC
385 global $DB, $USER;
386
387 $this->resetAfterTest(true);
388 // Create a course and assignment.
389 $coursedata['idnumber'] = 'idnumbercourse';
390 $coursedata['fullname'] = 'Lightwork Course';
391 $coursedata['summary'] = 'Lightwork Course description';
392 $coursedata['summaryformat'] = FORMAT_MOODLE;
393 $course = self::getDataGenerator()->create_course($coursedata);
394
395 $assigndata['course'] = $course->id;
396 $assigndata['name'] = 'lightwork assignment';
397
398 $assign = self::getDataGenerator()->create_module('assign', $assigndata);
399
400 // Create a manual enrolment record.
401 $manualenroldata['enrol'] = 'manual';
402 $manualenroldata['status'] = 0;
403 $manualenroldata['courseid'] = $course->id;
404 $enrolid = $DB->insert_record('enrol', $manualenroldata);
405
406 // Create a teacher and give them capabilities.
407 $context = context_course::instance($course->id);
408 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
780cf0a7 409 $context = context_module::instance($assign->cmid);
07df8c38
PC
410 $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
411
412 // Create the teacher's enrolment record.
413 $userenrolmentdata['status'] = 0;
414 $userenrolmentdata['enrolid'] = $enrolid;
415 $userenrolmentdata['userid'] = $USER->id;
416 $DB->insert_record('user_enrolments', $userenrolmentdata);
417
418 // Create a student and give them a user flag record.
419 $student = self::getDataGenerator()->create_user();
420 $userflag = new stdClass();
421 $userflag->assignment = $assign->id;
422 $userflag->userid = $student->id;
423 $userflag->locked = 0;
424 $userflag->mailed = 0;
425 $userflag->extensionduedate = 0;
426 $userflag->workflowstate = 'inmarking';
427 $userflag->allocatedmarker = $USER->id;
428
429 $DB->insert_record('assign_user_flags', $userflag);
430
431 $assignmentids[] = $assign->id;
432 $result = mod_assign_external::get_user_flags($assignmentids);
433
434 // We need to execute the return values cleaning process to simulate the web service server.
435 $result = external_api::clean_returnvalue(mod_assign_external::get_user_flags_returns(), $result);
436
437 // Check that the correct user flag information for the student is returned.
438 $this->assertEquals(1, count($result['assignments']));
439 $assignment = $result['assignments'][0];
440 $this->assertEquals($assign->id, $assignment['assignmentid']);
441 // Should be one user flag record.
442 $this->assertEquals(1, count($assignment['userflags']));
443 $userflag = $assignment['userflags'][0];
444 $this->assertEquals($student->id, $userflag['userid']);
445 $this->assertEquals(0, $userflag['locked']);
446 $this->assertEquals(0, $userflag['mailed']);
447 $this->assertEquals(0, $userflag['extensionduedate']);
448 $this->assertEquals('inmarking', $userflag['workflowstate']);
449 $this->assertEquals($USER->id, $userflag['allocatedmarker']);
450 }
451
452 /**
453 * Test get_user_mappings
454 */
05a6445a 455 public function test_get_user_mappings() {
07df8c38
PC
456 global $DB, $USER;
457
458 $this->resetAfterTest(true);
459 // Create a course and assignment.
460 $coursedata['idnumber'] = 'idnumbercourse';
461 $coursedata['fullname'] = 'Lightwork Course';
462 $coursedata['summary'] = 'Lightwork Course description';
463 $coursedata['summaryformat'] = FORMAT_MOODLE;
464 $course = self::getDataGenerator()->create_course($coursedata);
465
466 $assigndata['course'] = $course->id;
467 $assigndata['name'] = 'lightwork assignment';
468
469 $assign = self::getDataGenerator()->create_module('assign', $assigndata);
470
471 // Create a manual enrolment record.
472 $manualenroldata['enrol'] = 'manual';
473 $manualenroldata['status'] = 0;
474 $manualenroldata['courseid'] = $course->id;
475 $enrolid = $DB->insert_record('enrol', $manualenroldata);
476
477 // Create a teacher and give them capabilities.
478 $context = context_course::instance($course->id);
479 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
780cf0a7 480 $context = context_module::instance($assign->cmid);
07df8c38
PC
481 $this->assignUserCapability('mod/assign:revealidentities', $context->id, $roleid);
482
483 // Create the teacher's enrolment record.
484 $userenrolmentdata['status'] = 0;
485 $userenrolmentdata['enrolid'] = $enrolid;
486 $userenrolmentdata['userid'] = $USER->id;
487 $DB->insert_record('user_enrolments', $userenrolmentdata);
488
489 // Create a student and give them a user mapping record.
490 $student = self::getDataGenerator()->create_user();
491 $mapping = new stdClass();
492 $mapping->assignment = $assign->id;
493 $mapping->userid = $student->id;
494
495 $DB->insert_record('assign_user_mapping', $mapping);
496
497 $assignmentids[] = $assign->id;
498 $result = mod_assign_external::get_user_mappings($assignmentids);
499
500 // We need to execute the return values cleaning process to simulate the web service server.
501 $result = external_api::clean_returnvalue(mod_assign_external::get_user_mappings_returns(), $result);
502
503 // Check that the correct user mapping information for the student is returned.
504 $this->assertEquals(1, count($result['assignments']));
505 $assignment = $result['assignments'][0];
506 $this->assertEquals($assign->id, $assignment['assignmentid']);
507 // Should be one user mapping record.
508 $this->assertEquals(1, count($assignment['mappings']));
509 $mapping = $assignment['mappings'][0];
510 $this->assertEquals($student->id, $mapping['userid']);
511 }
512
05a6445a
DW
513 /**
514 * Test lock_submissions
515 */
516 public function test_lock_submissions() {
517 global $DB, $USER;
518
519 $this->resetAfterTest(true);
520 // Create a course and assignment and users.
521 $course = self::getDataGenerator()->create_course();
522
523 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
524 $params['course'] = $course->id;
525 $params['assignsubmission_onlinetext_enabled'] = 1;
526 $instance = $generator->create_instance($params);
527 $cm = get_coursemodule_from_instance('assign', $instance->id);
528 $context = context_module::instance($cm->id);
529
530 $assign = new assign($context, $cm, $course);
531
532 $student1 = self::getDataGenerator()->create_user();
533 $student2 = self::getDataGenerator()->create_user();
534 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
535 $this->getDataGenerator()->enrol_user($student1->id,
536 $course->id,
537 $studentrole->id);
538 $this->getDataGenerator()->enrol_user($student2->id,
539 $course->id,
540 $studentrole->id);
541 $teacher = self::getDataGenerator()->create_user();
542 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
543 $this->getDataGenerator()->enrol_user($teacher->id,
544 $course->id,
545 $teacherrole->id);
546
6d90ef2b 547 // Create a student1 with an online text submission.
05a6445a
DW
548 // Simulate a submission.
549 $this->setUser($student1);
550 $submission = $assign->get_user_submission($student1->id, true);
551 $data = new stdClass();
552 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
553 'text'=>'Submission text',
554 'format'=>FORMAT_MOODLE);
555 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
556 $plugin->save($submission, $data);
557
539af602 558 // Ready to test.
05a6445a
DW
559 $this->setUser($teacher);
560 $students = array($student1->id, $student2->id);
561 $result = mod_assign_external::lock_submissions($instance->id, $students);
7f45111e 562 $result = external_api::clean_returnvalue(mod_assign_external::lock_submissions_returns(), $result);
05a6445a
DW
563
564 // Check for 0 warnings.
565 $this->assertEquals(0, count($result));
566
567 $this->setUser($student2);
568 $submission = $assign->get_user_submission($student2->id, true);
569 $data = new stdClass();
570 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
571 'text'=>'Submission text',
572 'format'=>FORMAT_MOODLE);
573 $notices = array();
574 $this->setExpectedException('moodle_exception');
575 $assign->save_submission($data, $notices);
576 }
577
578 /**
579 * Test unlock_submissions
580 */
581 public function test_unlock_submissions() {
582 global $DB, $USER;
583
584 $this->resetAfterTest(true);
585 // Create a course and assignment and users.
586 $course = self::getDataGenerator()->create_course();
587
588 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
589 $params['course'] = $course->id;
590 $params['assignsubmission_onlinetext_enabled'] = 1;
591 $instance = $generator->create_instance($params);
592 $cm = get_coursemodule_from_instance('assign', $instance->id);
593 $context = context_module::instance($cm->id);
594
595 $assign = new assign($context, $cm, $course);
596
597 $student1 = self::getDataGenerator()->create_user();
598 $student2 = self::getDataGenerator()->create_user();
599 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
600 $this->getDataGenerator()->enrol_user($student1->id,
601 $course->id,
602 $studentrole->id);
603 $this->getDataGenerator()->enrol_user($student2->id,
604 $course->id,
605 $studentrole->id);
606 $teacher = self::getDataGenerator()->create_user();
607 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
608 $this->getDataGenerator()->enrol_user($teacher->id,
609 $course->id,
610 $teacherrole->id);
611
6d90ef2b 612 // Create a student1 with an online text submission.
05a6445a
DW
613 // Simulate a submission.
614 $this->setUser($student1);
615 $submission = $assign->get_user_submission($student1->id, true);
616 $data = new stdClass();
617 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
618 'text'=>'Submission text',
619 'format'=>FORMAT_MOODLE);
620 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
621 $plugin->save($submission, $data);
622
539af602 623 // Ready to test.
05a6445a
DW
624 $this->setUser($teacher);
625 $students = array($student1->id, $student2->id);
626 $result = mod_assign_external::lock_submissions($instance->id, $students);
7f45111e 627 $result = external_api::clean_returnvalue(mod_assign_external::lock_submissions_returns(), $result);
05a6445a
DW
628
629 // Check for 0 warnings.
630 $this->assertEquals(0, count($result));
631
632 $result = mod_assign_external::unlock_submissions($instance->id, $students);
7f45111e 633 $result = external_api::clean_returnvalue(mod_assign_external::unlock_submissions_returns(), $result);
05a6445a
DW
634
635 // Check for 0 warnings.
636 $this->assertEquals(0, count($result));
637
638 $this->setUser($student2);
639 $submission = $assign->get_user_submission($student2->id, true);
640 $data = new stdClass();
641 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
642 'text'=>'Submission text',
643 'format'=>FORMAT_MOODLE);
644 $notices = array();
645 $assign->save_submission($data, $notices);
646 }
647
648 /**
649 * Test submit_for_grading
650 */
651 public function test_submit_for_grading() {
652 global $DB, $USER;
653
654 $this->resetAfterTest(true);
655 // Create a course and assignment and users.
656 $course = self::getDataGenerator()->create_course();
657
658 set_config('submissionreceipts', 0, 'assign');
659 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
660 $params['course'] = $course->id;
661 $params['assignsubmission_onlinetext_enabled'] = 1;
662 $params['submissiondrafts'] = 1;
663 $params['sendnotifications'] = 0;
91327d96 664 $params['requiresubmissionstatement'] = 1;
05a6445a
DW
665 $instance = $generator->create_instance($params);
666 $cm = get_coursemodule_from_instance('assign', $instance->id);
667 $context = context_module::instance($cm->id);
668
669 $assign = new assign($context, $cm, $course);
670
671 $student1 = self::getDataGenerator()->create_user();
672 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
673 $this->getDataGenerator()->enrol_user($student1->id,
674 $course->id,
675 $studentrole->id);
676
677 // Create a student1 with an online text submission.
678 // Simulate a submission.
679 $this->setUser($student1);
680 $submission = $assign->get_user_submission($student1->id, true);
681 $data = new stdClass();
682 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
683 'text'=>'Submission text',
684 'format'=>FORMAT_MOODLE);
685 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
686 $plugin->save($submission, $data);
687
91327d96 688 $result = mod_assign_external::submit_for_grading($instance->id, false);
7f45111e 689 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
91327d96
DW
690
691 // Should be 1 fail because the submission statement was not aceptted.
692 $this->assertEquals(1, count($result));
693
694 $result = mod_assign_external::submit_for_grading($instance->id, true);
7f45111e 695 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
05a6445a
DW
696
697 // Check for 0 warnings.
698 $this->assertEquals(0, count($result));
699
700 $submission = $assign->get_user_submission($student1->id, false);
701
702 $this->assertEquals(ASSIGN_SUBMISSION_STATUS_SUBMITTED, $submission->status);
703 }
704
705 /**
706 * Test save_user_extensions
707 */
708 public function test_save_user_extensions() {
709 global $DB, $USER;
710
711 $this->resetAfterTest(true);
712 // Create a course and assignment and users.
713 $course = self::getDataGenerator()->create_course();
714
715 $teacher = self::getDataGenerator()->create_user();
716 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
717 $this->getDataGenerator()->enrol_user($teacher->id,
718 $course->id,
719 $teacherrole->id);
720 $this->setUser($teacher);
721
722 $now = time();
723 $yesterday = $now - 24*60*60;
724 $tomorrow = $now + 24*60*60;
725 set_config('submissionreceipts', 0, 'assign');
726 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
727 $params['course'] = $course->id;
728 $params['submissiondrafts'] = 1;
729 $params['sendnotifications'] = 0;
730 $params['duedate'] = $yesterday;
731 $params['cutoffdate'] = $now - 10;
732 $instance = $generator->create_instance($params);
733 $cm = get_coursemodule_from_instance('assign', $instance->id);
734 $context = context_module::instance($cm->id);
735
736 $assign = new assign($context, $cm, $course);
737
738 $student1 = self::getDataGenerator()->create_user();
739 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
740 $this->getDataGenerator()->enrol_user($student1->id,
741 $course->id,
742 $studentrole->id);
743
744 $this->setUser($student1);
91327d96 745 $result = mod_assign_external::submit_for_grading($instance->id, true);
7f45111e 746 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
05a6445a
DW
747
748 // Check for 0 warnings.
749 $this->assertEquals(1, count($result));
750
751 $this->setUser($teacher);
752 $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow));
7f45111e 753 $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
05a6445a
DW
754 $this->assertEquals(1, count($result));
755
756 $this->setUser($teacher);
757 $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($yesterday - 10));
7f45111e 758 $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
05a6445a
DW
759 $this->assertEquals(1, count($result));
760
761 $this->setUser($teacher);
762 $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($tomorrow));
7f45111e 763 $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
05a6445a
DW
764 $this->assertEquals(0, count($result));
765
766 $this->setUser($student1);
91327d96 767 $result = mod_assign_external::submit_for_grading($instance->id, true);
7f45111e 768 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
05a6445a
DW
769 $this->assertEquals(0, count($result));
770
771 $this->setUser($student1);
772 $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow));
7f45111e 773 $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
05a6445a
DW
774
775 }
776
777 /**
778 * Test reveal_identities
779 */
780 public function test_reveal_identities() {
781 global $DB, $USER;
782
783 $this->resetAfterTest(true);
784 // Create a course and assignment and users.
785 $course = self::getDataGenerator()->create_course();
786
787 $teacher = self::getDataGenerator()->create_user();
788 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
789 $this->getDataGenerator()->enrol_user($teacher->id,
790 $course->id,
791 $teacherrole->id);
792 $this->setUser($teacher);
793
794 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
795 $params['course'] = $course->id;
796 $params['submissiondrafts'] = 1;
797 $params['sendnotifications'] = 0;
798 $params['blindmarking'] = 1;
799 $instance = $generator->create_instance($params);
800 $cm = get_coursemodule_from_instance('assign', $instance->id);
801 $context = context_module::instance($cm->id);
802
803 $assign = new assign($context, $cm, $course);
804
805 $student1 = self::getDataGenerator()->create_user();
806 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
807 $this->getDataGenerator()->enrol_user($student1->id,
808 $course->id,
809 $studentrole->id);
810
811 $this->setUser($student1);
812 $this->setExpectedException('required_capability_exception');
813 $result = mod_assign_external::reveal_identities($instance->id);
7f45111e 814 $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
05a6445a
DW
815 $this->assertEquals(1, count($result));
816 $this->assertEquals(true, $assign->is_blind_marking());
817
818 $this->setUser($teacher);
819 $result = mod_assign_external::reveal_identities($instance->id);
7f45111e 820 $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
05a6445a
DW
821 $this->assertEquals(0, count($result));
822 $this->assertEquals(false, $assign->is_blind_marking());
823
824 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
825 $params['course'] = $course->id;
826 $params['submissiondrafts'] = 1;
827 $params['sendnotifications'] = 0;
828 $params['blindmarking'] = 0;
829 $instance = $generator->create_instance($params);
830 $cm = get_coursemodule_from_instance('assign', $instance->id);
831 $context = context_module::instance($cm->id);
832
833 $assign = new assign($context, $cm, $course);
834 $result = mod_assign_external::reveal_identities($instance->id);
7f45111e 835 $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
05a6445a
DW
836 $this->assertEquals(1, count($result));
837 $this->assertEquals(false, $assign->is_blind_marking());
838
839 }
840
841 /**
842 * Test revert_submissions_to_draft
843 */
844 public function test_revert_submissions_to_draft() {
845 global $DB, $USER;
846
847 $this->resetAfterTest(true);
848 set_config('submissionreceipts', 0, 'assign');
849 // Create a course and assignment and users.
850 $course = self::getDataGenerator()->create_course();
851
852 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
853 $params['course'] = $course->id;
854 $params['sendnotifications'] = 0;
855 $params['submissiondrafts'] = 1;
856 $instance = $generator->create_instance($params);
857 $cm = get_coursemodule_from_instance('assign', $instance->id);
858 $context = context_module::instance($cm->id);
859
860 $assign = new assign($context, $cm, $course);
861
862 $student1 = self::getDataGenerator()->create_user();
863 $student2 = self::getDataGenerator()->create_user();
864 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
865 $this->getDataGenerator()->enrol_user($student1->id,
866 $course->id,
867 $studentrole->id);
868 $this->getDataGenerator()->enrol_user($student2->id,
869 $course->id,
870 $studentrole->id);
871 $teacher = self::getDataGenerator()->create_user();
872 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
873 $this->getDataGenerator()->enrol_user($teacher->id,
874 $course->id,
875 $teacherrole->id);
876
877 // Create a student1 with an online text submission.
878 // Simulate a submission.
879 $this->setUser($student1);
91327d96 880 $result = mod_assign_external::submit_for_grading($instance->id, true);
7f45111e 881 $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
05a6445a
DW
882 $this->assertEquals(0, count($result));
883
539af602 884 // Ready to test.
05a6445a
DW
885 $this->setUser($teacher);
886 $students = array($student1->id, $student2->id);
887 $result = mod_assign_external::revert_submissions_to_draft($instance->id, array($student1->id));
7f45111e 888 $result = external_api::clean_returnvalue(mod_assign_external::revert_submissions_to_draft_returns(), $result);
05a6445a
DW
889
890 // Check for 0 warnings.
891 $this->assertEquals(0, count($result));
892
893 }
894
895 /**
896 * Test save_submission
897 */
898 public function test_save_submission() {
899 global $DB, $USER;
900
901 $this->resetAfterTest(true);
902 // Create a course and assignment and users.
903 $course = self::getDataGenerator()->create_course();
904
905 $teacher = self::getDataGenerator()->create_user();
906 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
907 $this->getDataGenerator()->enrol_user($teacher->id,
908 $course->id,
909 $teacherrole->id);
910 $this->setUser($teacher);
911
912 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
913 $params['course'] = $course->id;
914 $params['assignsubmission_onlinetext_enabled'] = 1;
915 $params['assignsubmission_file_enabled'] = 1;
916 $params['assignsubmission_file_maxfiles'] = 5;
917 $params['assignsubmission_file_maxsizebytes'] = 1024*1024;
918 $instance = $generator->create_instance($params);
919 $cm = get_coursemodule_from_instance('assign', $instance->id);
920 $context = context_module::instance($cm->id);
921
922 $assign = new assign($context, $cm, $course);
923
924 $student1 = self::getDataGenerator()->create_user();
925 $student2 = self::getDataGenerator()->create_user();
926 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
927 $this->getDataGenerator()->enrol_user($student1->id,
928 $course->id,
929 $studentrole->id);
930 $this->getDataGenerator()->enrol_user($student2->id,
931 $course->id,
932 $studentrole->id);
933 // Create a student1 with an online text submission.
934 // Simulate a submission.
935 $this->setUser($student1);
936
937 // Create a file in a draft area.
938 $draftidfile = file_get_unused_draft_itemid();
939
940 $usercontext = context_user::instance($student1->id);
941 $filerecord = array(
942 'contextid' => $usercontext->id,
943 'component' => 'user',
944 'filearea' => 'draft',
945 'itemid' => $draftidfile,
946 'filepath' => '/',
947 'filename' => 'testtext.txt',
948 );
949
950 $fs = get_file_storage();
951 $fs->create_file_from_string($filerecord, 'text contents');
952
953 // Create another file in a different draft area.
954 $draftidonlinetext = file_get_unused_draft_itemid();
955
956 $filerecord = array(
957 'contextid' => $usercontext->id,
958 'component' => 'user',
959 'filearea' => 'draft',
960 'itemid' => $draftidonlinetext,
961 'filepath' => '/',
962 'filename' => 'shouldbeanimage.txt',
963 );
964
965 $fs->create_file_from_string($filerecord, 'image contents (not really)');
966
539af602 967 // Now try a submission.
05a6445a
DW
968 $submissionpluginparams = array();
969 $submissionpluginparams['files_filemanager'] = $draftidfile;
970 $onlinetexteditorparams = array('text'=>'Yeeha!',
971 'format'=>1,
972 'itemid'=>$draftidonlinetext);
973 $submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams;
974 $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
7f45111e 975 $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result);
05a6445a
DW
976
977 $this->assertEquals(0, count($result));
978
711f9468
JL
979 // Set up a due and cutoff passed date.
980 $instance->duedate = time() - WEEKSECS;
981 $instance->cutoffdate = time() - WEEKSECS;
982 $DB->update_record('assign', $instance);
983
984 $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
985 $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result);
986
987 $this->assertCount(1, $result);
988 $this->assertEquals(get_string('duedatereached', 'assign'), $result[0]['item']);
05a6445a
DW
989 }
990
991 /**
992 * Test save_grade
993 */
994 public function test_save_grade() {
995 global $DB, $USER;
996
997 $this->resetAfterTest(true);
998 // Create a course and assignment and users.
999 $course = self::getDataGenerator()->create_course();
1000
1001 $teacher = self::getDataGenerator()->create_user();
1002 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
1003 $this->getDataGenerator()->enrol_user($teacher->id,
1004 $course->id,
1005 $teacherrole->id);
1006 $this->setUser($teacher);
1007
1008 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1009 $params['course'] = $course->id;
1010 $params['assignfeedback_file_enabled'] = 1;
1011 $params['assignfeedback_comments_enabled'] = 1;
1012 $instance = $generator->create_instance($params);
1013 $cm = get_coursemodule_from_instance('assign', $instance->id);
1014 $context = context_module::instance($cm->id);
1015
1016 $assign = new assign($context, $cm, $course);
1017
1018 $student1 = self::getDataGenerator()->create_user();
1019 $student2 = self::getDataGenerator()->create_user();
40c3dacf 1020 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
05a6445a
DW
1021 $this->getDataGenerator()->enrol_user($student1->id,
1022 $course->id,
1023 $studentrole->id);
1024 $this->getDataGenerator()->enrol_user($student2->id,
1025 $course->id,
1026 $studentrole->id);
1027 // Simulate a grade.
1028 $this->setUser($teacher);
1029
1030 // Create a file in a draft area.
1031 $draftidfile = file_get_unused_draft_itemid();
1032
1033 $usercontext = context_user::instance($teacher->id);
1034 $filerecord = array(
1035 'contextid' => $usercontext->id,
1036 'component' => 'user',
1037 'filearea' => 'draft',
1038 'itemid' => $draftidfile,
1039 'filepath' => '/',
1040 'filename' => 'testtext.txt',
1041 );
1042
1043 $fs = get_file_storage();
1044 $fs->create_file_from_string($filerecord, 'text contents');
1045
539af602 1046 // Now try a grade.
05a6445a
DW
1047 $feedbackpluginparams = array();
1048 $feedbackpluginparams['files_filemanager'] = $draftidfile;
40c3dacf
PC
1049 $feedbackeditorparams = array('text' => 'Yeeha!',
1050 'format' => 1);
05a6445a 1051 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
539af602
DW
1052 $result = mod_assign_external::save_grade($instance->id,
1053 $student1->id,
1054 50.0,
1055 -1,
1056 true,
1057 'released',
1058 false,
1059 $feedbackpluginparams);
05a6445a 1060 // No warnings.
7f45111e 1061 $this->assertNull($result);
05a6445a
DW
1062
1063 $result = mod_assign_external::get_grades(array($instance->id));
7f45111e 1064 $result = external_api::clean_returnvalue(mod_assign_external::get_grades_returns(), $result);
05a6445a
DW
1065
1066 $this->assertEquals($result['assignments'][0]['grades'][0]['grade'], '50.0');
05a6445a
DW
1067 }
1068
40c3dacf
PC
1069 /**
1070 * Test save grades with advanced grading data
1071 */
1072 public function test_save_grades_with_advanced_grading() {
1073 global $DB, $USER;
1074
1075 $this->resetAfterTest(true);
1076 // Create a course and assignment and users.
1077 $course = self::getDataGenerator()->create_course();
1078
1079 $teacher = self::getDataGenerator()->create_user();
1080 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1081 $this->getDataGenerator()->enrol_user($teacher->id,
1082 $course->id,
1083 $teacherrole->id);
1084
1085 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1086 $params['course'] = $course->id;
1087 $params['assignfeedback_file_enabled'] = 0;
1088 $params['assignfeedback_comments_enabled'] = 0;
1089 $instance = $generator->create_instance($params);
1090 $cm = get_coursemodule_from_instance('assign', $instance->id);
1091 $context = context_module::instance($cm->id);
1092
1093 $assign = new assign($context, $cm, $course);
1094
1095 $student1 = self::getDataGenerator()->create_user();
1096 $student2 = self::getDataGenerator()->create_user();
1097 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1098 $this->getDataGenerator()->enrol_user($student1->id,
1099 $course->id,
1100 $studentrole->id);
1101 $this->getDataGenerator()->enrol_user($student2->id,
1102 $course->id,
1103 $studentrole->id);
1104
1105 $this->setUser($teacher);
1106
1107 $feedbackpluginparams = array();
1108 $feedbackpluginparams['files_filemanager'] = 0;
1109 $feedbackeditorparams = array('text' => '', 'format' => 1);
1110 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1111
1112 // Create advanced grading data.
1113 // Create grading area.
1114 $gradingarea = array(
1115 'contextid' => $context->id,
1116 'component' => 'mod_assign',
1117 'areaname' => 'submissions',
1118 'activemethod' => 'rubric'
1119 );
1120 $areaid = $DB->insert_record('grading_areas', $gradingarea);
1121
1122 // Create a rubric grading definition.
1123 $rubricdefinition = array (
1124 'areaid' => $areaid,
1125 'method' => 'rubric',
1126 'name' => 'test',
1127 'status' => 20,
1128 'copiedfromid' => 1,
1129 'timecreated' => 1,
1130 'usercreated' => $teacher->id,
1131 'timemodified' => 1,
1132 'usermodified' => $teacher->id,
1133 'timecopied' => 0
1134 );
1135 $definitionid = $DB->insert_record('grading_definitions', $rubricdefinition);
1136
1137 // Create a criterion with a level.
1138 $rubriccriteria = array (
1139 'definitionid' => $definitionid,
1140 'sortorder' => 1,
1141 'description' => 'Demonstrate an understanding of disease control',
1142 'descriptionformat' => 0
1143 );
1144 $criterionid = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria);
1145 $rubriclevel1 = array (
1146 'criterionid' => $criterionid,
1147 'score' => 50,
1148 'definition' => 'pass',
1149 'definitionformat' => 0
1150 );
1151 $rubriclevel2 = array (
1152 'criterionid' => $criterionid,
1153 'score' => 100,
1154 'definition' => 'excellent',
1155 'definitionformat' => 0
1156 );
1157 $rubriclevel3 = array (
1158 'criterionid' => $criterionid,
1159 'score' => 0,
1160 'definition' => 'fail',
1161 'definitionformat' => 0
1162 );
1163 $levelid1 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel1);
1164 $levelid2 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel2);
1165 $levelid3 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel3);
1166
1167 // Create the filling.
1168 $student1filling = array (
1169 'criterionid' => $criterionid,
1170 'levelid' => $levelid1,
1171 'remark' => 'well done you passed',
1172 'remarkformat' => 0
1173 );
1174
1175 $student2filling = array (
1176 'criterionid' => $criterionid,
1177 'levelid' => $levelid2,
1178 'remark' => 'Excellent work',
1179 'remarkformat' => 0
1180 );
1181
1182 $student1criteria = array(array('criterionid' => $criterionid, 'fillings' => array($student1filling)));
1183 $student1advancedgradingdata = array('rubric' => array('criteria' => $student1criteria));
1184
1185 $student2criteria = array(array('criterionid' => $criterionid, 'fillings' => array($student2filling)));
1186 $student2advancedgradingdata = array('rubric' => array('criteria' => $student2criteria));
1187
1188 $grades = array();
1189 $student1gradeinfo = array();
1190 $student1gradeinfo['userid'] = $student1->id;
1191 $student1gradeinfo['grade'] = 0; // Ignored since advanced grading is being used.
1192 $student1gradeinfo['attemptnumber'] = -1;
1193 $student1gradeinfo['addattempt'] = true;
1194 $student1gradeinfo['workflowstate'] = 'released';
1195 $student1gradeinfo['plugindata'] = $feedbackpluginparams;
1196 $student1gradeinfo['advancedgradingdata'] = $student1advancedgradingdata;
1197 $grades[] = $student1gradeinfo;
1198
1199 $student2gradeinfo = array();
1200 $student2gradeinfo['userid'] = $student2->id;
1201 $student2gradeinfo['grade'] = 0; // Ignored since advanced grading is being used.
1202 $student2gradeinfo['attemptnumber'] = -1;
1203 $student2gradeinfo['addattempt'] = true;
1204 $student2gradeinfo['workflowstate'] = 'released';
1205 $student2gradeinfo['plugindata'] = $feedbackpluginparams;
1206 $student2gradeinfo['advancedgradingdata'] = $student2advancedgradingdata;
1207 $grades[] = $student2gradeinfo;
1208
1209 $result = mod_assign_external::save_grades($instance->id, false, $grades);
7f45111e 1210 $this->assertNull($result);
40c3dacf
PC
1211
1212 $student1grade = $DB->get_record('assign_grades',
1213 array('userid' => $student1->id, 'assignment' => $instance->id),
1214 '*',
1215 MUST_EXIST);
1216 $this->assertEquals($student1grade->grade, '50.0');
1217
1218 $student2grade = $DB->get_record('assign_grades',
1219 array('userid' => $student2->id, 'assignment' => $instance->id),
1220 '*',
1221 MUST_EXIST);
1222 $this->assertEquals($student2grade->grade, '100.0');
1223 }
1224
1225 /**
1226 * Test save grades for a team submission
1227 */
1228 public function test_save_grades_with_group_submission() {
1229 global $DB, $USER, $CFG;
1230 require_once($CFG->dirroot . '/group/lib.php');
1231
1232 $this->resetAfterTest(true);
1233 // Create a course and assignment and users.
1234 $course = self::getDataGenerator()->create_course();
1235
1236 $teacher = self::getDataGenerator()->create_user();
1237 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1238 $this->getDataGenerator()->enrol_user($teacher->id,
1239 $course->id,
1240 $teacherrole->id);
1241
1242 $groupingdata = array();
1243 $groupingdata['courseid'] = $course->id;
1244 $groupingdata['name'] = 'Group assignment grouping';
1245
1246 $grouping = self::getDataGenerator()->create_grouping($groupingdata);
1247
1248 $group1data = array();
1249 $group1data['courseid'] = $course->id;
1250 $group1data['name'] = 'Team 1';
1251 $group2data = array();
1252 $group2data['courseid'] = $course->id;
1253 $group2data['name'] = 'Team 2';
1254
1255 $group1 = self::getDataGenerator()->create_group($group1data);
1256 $group2 = self::getDataGenerator()->create_group($group2data);
1257
1258 groups_assign_grouping($grouping->id, $group1->id);
1259 groups_assign_grouping($grouping->id, $group2->id);
1260
1261 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1262 $params['course'] = $course->id;
1263 $params['teamsubmission'] = 1;
1264 $params['teamsubmissiongroupingid'] = $grouping->id;
1265 $instance = $generator->create_instance($params);
1266 $cm = get_coursemodule_from_instance('assign', $instance->id);
1267 $context = context_module::instance($cm->id);
1268
1269 $assign = new assign($context, $cm, $course);
1270
1271 $student1 = self::getDataGenerator()->create_user();
1272 $student2 = self::getDataGenerator()->create_user();
1273 $student3 = self::getDataGenerator()->create_user();
1274 $student4 = self::getDataGenerator()->create_user();
1275 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1276 $this->getDataGenerator()->enrol_user($student1->id,
1277 $course->id,
1278 $studentrole->id);
1279 $this->getDataGenerator()->enrol_user($student2->id,
1280 $course->id,
1281 $studentrole->id);
1282 $this->getDataGenerator()->enrol_user($student3->id,
1283 $course->id,
1284 $studentrole->id);
1285 $this->getDataGenerator()->enrol_user($student4->id,
1286 $course->id,
1287 $studentrole->id);
1288
1289 groups_add_member($group1->id, $student1->id);
1290 groups_add_member($group1->id, $student2->id);
1291 groups_add_member($group1->id, $student3->id);
1292 groups_add_member($group2->id, $student4->id);
1293 $this->setUser($teacher);
1294
1295 $feedbackpluginparams = array();
1296 $feedbackpluginparams['files_filemanager'] = 0;
1297 $feedbackeditorparams = array('text' => '', 'format' => 1);
1298 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1299
1300 $grades1 = array();
1301 $student1gradeinfo = array();
1302 $student1gradeinfo['userid'] = $student1->id;
1303 $student1gradeinfo['grade'] = 50;
1304 $student1gradeinfo['attemptnumber'] = -1;
1305 $student1gradeinfo['addattempt'] = true;
1306 $student1gradeinfo['workflowstate'] = 'released';
1307 $student1gradeinfo['plugindata'] = $feedbackpluginparams;
1308 $grades1[] = $student1gradeinfo;
1309
1310 $student2gradeinfo = array();
1311 $student2gradeinfo['userid'] = $student2->id;
1312 $student2gradeinfo['grade'] = 75;
1313 $student2gradeinfo['attemptnumber'] = -1;
1314 $student2gradeinfo['addattempt'] = true;
1315 $student2gradeinfo['workflowstate'] = 'released';
1316 $student2gradeinfo['plugindata'] = $feedbackpluginparams;
1317 $grades1[] = $student2gradeinfo;
1318
1319 $this->setExpectedException('invalid_parameter_exception');
1320 // Expect an exception since 2 grades have been submitted for the same team.
1321 $result = mod_assign_external::save_grades($instance->id, true, $grades1);
7f45111e 1322 $result = external_api::clean_returnvalue(mod_assign_external::save_grades_returns(), $result);
40c3dacf
PC
1323
1324 $grades2 = array();
1325 $student3gradeinfo = array();
1326 $student3gradeinfo['userid'] = $student3->id;
1327 $student3gradeinfo['grade'] = 50;
1328 $student3gradeinfo['attemptnumber'] = -1;
1329 $student3gradeinfo['addattempt'] = true;
1330 $student3gradeinfo['workflowstate'] = 'released';
1331 $student3gradeinfo['plugindata'] = $feedbackpluginparams;
1332 $grades2[] = $student3gradeinfo;
1333
1334 $student4gradeinfo = array();
1335 $student4gradeinfo['userid'] = $student4->id;
1336 $student4gradeinfo['grade'] = 75;
1337 $student4gradeinfo['attemptnumber'] = -1;
1338 $student4gradeinfo['addattempt'] = true;
1339 $student4gradeinfo['workflowstate'] = 'released';
1340 $student4gradeinfo['plugindata'] = $feedbackpluginparams;
1341 $grades2[] = $student4gradeinfo;
1342 $result = mod_assign_external::save_grades($instance->id, true, $grades2);
7f45111e 1343 $result = external_api::clean_returnvalue(mod_assign_external::save_grades_returns(), $result);
40c3dacf
PC
1344 // There should be no warnings.
1345 $this->assertEquals(0, count($result));
1346
1347 $student3grade = $DB->get_record('assign_grades',
1348 array('userid' => $student3->id, 'assignment' => $instance->id),
1349 '*',
1350 MUST_EXIST);
1351 $this->assertEquals($student3grade->grade, '50.0');
1352
1353 $student4grade = $DB->get_record('assign_grades',
1354 array('userid' => $student4->id, 'assignment' => $instance->id),
1355 '*',
1356 MUST_EXIST);
1357 $this->assertEquals($student4grade->grade, '75.0');
1358 }
1359
05a6445a
DW
1360 /**
1361 * Test copy_previous_attempt
1362 */
1363 public function test_copy_previous_attempt() {
1364 global $DB, $USER;
1365
1366 $this->resetAfterTest(true);
1367 // Create a course and assignment and users.
1368 $course = self::getDataGenerator()->create_course();
1369
1370 $teacher = self::getDataGenerator()->create_user();
1371 $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
1372 $this->getDataGenerator()->enrol_user($teacher->id,
1373 $course->id,
1374 $teacherrole->id);
1375 $this->setUser($teacher);
1376
1377 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1378 $params['course'] = $course->id;
1379 $params['assignsubmission_onlinetext_enabled'] = 1;
1380 $params['assignsubmission_file_enabled'] = 0;
1381 $params['assignfeedback_file_enabled'] = 0;
1382 $params['attemptreopenmethod'] = 'manual';
1383 $params['maxattempts'] = 5;
1384 $instance = $generator->create_instance($params);
1385 $cm = get_coursemodule_from_instance('assign', $instance->id);
1386 $context = context_module::instance($cm->id);
1387
1388 $assign = new assign($context, $cm, $course);
1389
1390 $student1 = self::getDataGenerator()->create_user();
1391 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
1392 $this->getDataGenerator()->enrol_user($student1->id,
1393 $course->id,
1394 $studentrole->id);
539af602 1395 // Now try a submission.
05a6445a
DW
1396 $this->setUser($student1);
1397 $draftidonlinetext = file_get_unused_draft_itemid();
1398 $submissionpluginparams = array();
1399 $onlinetexteditorparams = array('text'=>'Yeeha!',
1400 'format'=>1,
1401 'itemid'=>$draftidonlinetext);
1402 $submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams;
1403 $submissionpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
1404 $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
7f45111e 1405 $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result);
05a6445a
DW
1406
1407 $this->setUser($teacher);
1408 // Add a grade and reopen the attempt.
539af602 1409 // Now try a grade.
05a6445a
DW
1410 $feedbackpluginparams = array();
1411 $feedbackpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
1412 $feedbackeditorparams = array('text'=>'Yeeha!',
1413 'format'=>1);
1414 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
539af602
DW
1415 $result = mod_assign_external::save_grade($instance->id,
1416 $student1->id,
1417 50.0,
1418 -1,
1419 true,
1420 'released',
1421 false,
1422 $feedbackpluginparams);
7f45111e 1423 $this->assertNull($result);
05a6445a
DW
1424
1425 $this->setUser($student1);
1426 // Now copy the previous attempt.
1427 $result = mod_assign_external::copy_previous_attempt($instance->id);
7f45111e 1428 $result = external_api::clean_returnvalue(mod_assign_external::copy_previous_attempt_returns(), $result);
05a6445a
DW
1429 // No warnings.
1430 $this->assertEquals(0, count($result));
1431
1432 $this->setUser($teacher);
1433 $result = mod_assign_external::get_submissions(array($instance->id));
7f45111e 1434 $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result);
05a6445a
DW
1435
1436 // Check we are now on the second attempt.
1437 $this->assertEquals($result['assignments'][0]['submissions'][0]['attemptnumber'], 1);
1438 // Check the plugins data is not empty.
1439 $this->assertNotEmpty($result['assignments'][0]['submissions'][0]['plugins']);
1440
1441 }
e8b443df
PC
1442
1443 /**
1444 * Test set_user_flags
1445 */
1446 public function test_set_user_flags() {
1447 global $DB, $USER;
1448
1449 $this->resetAfterTest(true);
1450 // Create a course and assignment.
1451 $coursedata['idnumber'] = 'idnumbercourse';
1452 $coursedata['fullname'] = 'Lightwork Course';
1453 $coursedata['summary'] = 'Lightwork Course description';
1454 $coursedata['summaryformat'] = FORMAT_MOODLE;
1455 $course = self::getDataGenerator()->create_course($coursedata);
1456
1457 $assigndata['course'] = $course->id;
1458 $assigndata['name'] = 'lightwork assignment';
1459
1460 $assign = self::getDataGenerator()->create_module('assign', $assigndata);
1461
1462 // Create a manual enrolment record.
1463 $manualenroldata['enrol'] = 'manual';
1464 $manualenroldata['status'] = 0;
1465 $manualenroldata['courseid'] = $course->id;
1466 $enrolid = $DB->insert_record('enrol', $manualenroldata);
1467
1468 // Create a teacher and give them capabilities.
1469 $context = context_course::instance($course->id);
1470 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
780cf0a7 1471 $context = context_module::instance($assign->cmid);
e8b443df
PC
1472 $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
1473
1474 // Create the teacher's enrolment record.
1475 $userenrolmentdata['status'] = 0;
1476 $userenrolmentdata['enrolid'] = $enrolid;
1477 $userenrolmentdata['userid'] = $USER->id;
1478 $DB->insert_record('user_enrolments', $userenrolmentdata);
1479
1480 // Create a student.
1481 $student = self::getDataGenerator()->create_user();
1482
1483 // Create test user flags record.
1484 $userflags = array();
1485 $userflag['userid'] = $student->id;
1486 $userflag['workflowstate'] = 'inmarking';
1487 $userflag['allocatedmarker'] = $USER->id;
1488 $userflags = array($userflag);
1489
1490 $createduserflags = mod_assign_external::set_user_flags($assign->id, $userflags);
1491 // We need to execute the return values cleaning process to simulate the web service server.
1492 $createduserflags = external_api::clean_returnvalue(mod_assign_external::set_user_flags_returns(), $createduserflags);
1493
1494 $this->assertEquals($student->id, $createduserflags[0]['userid']);
1495 $createduserflag = $DB->get_record('assign_user_flags', array('id' => $createduserflags[0]['id']));
1496
1497 // Confirm that all data was inserted correctly.
1498 $this->assertEquals($student->id, $createduserflag->userid);
1499 $this->assertEquals($assign->id, $createduserflag->assignment);
1500 $this->assertEquals(0, $createduserflag->locked);
1501 $this->assertEquals(2, $createduserflag->mailed);
1502 $this->assertEquals(0, $createduserflag->extensionduedate);
1503 $this->assertEquals('inmarking', $createduserflag->workflowstate);
1504 $this->assertEquals($USER->id, $createduserflag->allocatedmarker);
1505
1506 // Create update data.
1507 $userflags = array();
1508 $userflag['userid'] = $createduserflag->userid;
1509 $userflag['workflowstate'] = 'readyforreview';
1510 $userflags = array($userflag);
1511
1512 $updateduserflags = mod_assign_external::set_user_flags($assign->id, $userflags);
1513 // We need to execute the return values cleaning process to simulate the web service server.
1514 $updateduserflags = external_api::clean_returnvalue(mod_assign_external::set_user_flags_returns(), $updateduserflags);
1515
1516 $this->assertEquals($student->id, $updateduserflags[0]['userid']);
1517 $updateduserflag = $DB->get_record('assign_user_flags', array('id' => $updateduserflags[0]['id']));
1518
1519 // Confirm that all data was updated correctly.
1520 $this->assertEquals($student->id, $updateduserflag->userid);
1521 $this->assertEquals($assign->id, $updateduserflag->assignment);
1522 $this->assertEquals(0, $updateduserflag->locked);
1523 $this->assertEquals(2, $updateduserflag->mailed);
1524 $this->assertEquals(0, $updateduserflag->extensionduedate);
1525 $this->assertEquals('readyforreview', $updateduserflag->workflowstate);
1526 $this->assertEquals($USER->id, $updateduserflag->allocatedmarker);
1527 }
1528
91a12bc6
JL
1529 /**
1530 * Test view_grading_table
1531 */
64d64656 1532 public function test_view_grading_table_invalid_instance() {
91a12bc6
JL
1533 global $DB;
1534
1535 $this->resetAfterTest(true);
1536
91a12bc6
JL
1537 // Setup test data.
1538 $course = $this->getDataGenerator()->create_course();
1539 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1540 $context = context_module::instance($assign->cmid);
1541 $cm = get_coursemodule_from_instance('assign', $assign->id);
1542
1543 // Test invalid instance id.
64d64656
AN
1544 $this->setExpectedExceptionRegexp('dml_missing_record_exception');
1545 mod_assign_external::view_grading_table(0);
1546 }
1547
1548 /**
1549 * Test view_grading_table
1550 */
1551 public function test_view_grading_table_not_enrolled() {
1552 global $DB;
1553
1554 $this->resetAfterTest(true);
1555
1556 // Setup test data.
1557 $course = $this->getDataGenerator()->create_course();
1558 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1559 $context = context_module::instance($assign->cmid);
1560 $cm = get_coursemodule_from_instance('assign', $assign->id);
91a12bc6
JL
1561
1562 // Test not-enrolled user.
1563 $user = self::getDataGenerator()->create_user();
1564 $this->setUser($user);
64d64656
AN
1565
1566 $this->setExpectedException('require_login_exception');
1567 mod_assign_external::view_grading_table($assign->id);
1568 }
1569
1570 /**
1571 * Test view_grading_table
1572 */
1573 public function test_view_grading_table_correct() {
1574 global $DB;
1575
1576 $this->resetAfterTest(true);
1577
1578 // Setup test data.
1579 $course = $this->getDataGenerator()->create_course();
1580 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1581 $context = context_module::instance($assign->cmid);
1582 $cm = get_coursemodule_from_instance('assign', $assign->id);
91a12bc6
JL
1583
1584 // Test user with full capabilities.
64d64656
AN
1585 $user = self::getDataGenerator()->create_user();
1586 $this->setUser($user);
91a12bc6
JL
1587 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1588 $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
1589
1590 // Trigger and capture the event.
1591 $sink = $this->redirectEvents();
1592
1593 $result = mod_assign_external::view_grading_table($assign->id);
1594 $result = external_api::clean_returnvalue(mod_assign_external::view_grading_table_returns(), $result);
1595
1596 $events = $sink->get_events();
1597 $this->assertCount(1, $events);
1598 $event = array_shift($events);
1599
1600 // Checking that the event contains the expected values.
1601 $this->assertInstanceOf('\mod_assign\event\grading_table_viewed', $event);
1602 $this->assertEquals($context, $event->get_context());
1603 $moodleurl = new \moodle_url('/mod/assign/view.php', array('id' => $cm->id));
1604 $this->assertEquals($moodleurl, $event->get_url());
1605 $this->assertEventContextNotUsed($event);
1606 $this->assertNotEmpty($event->get_name());
64d64656
AN
1607 }
1608
1609 /**
1610 * Test view_grading_table
1611 */
1612 public function test_view_grading_table_without_capability() {
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 user with no capabilities.
64d64656
AN
1624 $user = self::getDataGenerator()->create_user();
1625 $this->setUser($user);
1626 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1627 $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
1628
91a12bc6 1629 // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
64d64656 1630 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
91a12bc6 1631 assign_capability('mod/assign:view', CAP_PROHIBIT, $teacherrole->id, $context->id);
0bf6c0be 1632 // Empty all the caches that may be affected by this change.
91a12bc6 1633 accesslib_clear_all_caches_for_unit_testing();
0bf6c0be 1634 course_modinfo::clear_instance_cache();
91a12bc6 1635
64d64656
AN
1636 $this->setExpectedException('require_login_exception', 'Course or activity not accessible. (Activity is hidden)');
1637 mod_assign_external::view_grading_table($assign->id);
91a12bc6
JL
1638 }
1639
7cc21061
JL
1640 /**
1641 * Test subplugins availability
1642 */
1643 public function test_subplugins_availability() {
1644 global $CFG;
1645
1646 require_once($CFG->dirroot . '/mod/assign/adminlib.php');
1647 $this->resetAfterTest(true);
1648
1649 // Hide assignment file submissiong plugin.
1650 $pluginmanager = new assign_plugin_manager('assignsubmission');
1651 $pluginmanager->hide_plugin('file');
1652 $parameters = mod_assign_external::save_submission_parameters();
1653
1654 $this->assertTrue(!isset($parameters->keys['plugindata']->keys['files_filemanager']));
1655
1656 // Show it again and check that the value is returned as optional.
1657 $pluginmanager->show_plugin('file');
1658 $parameters = mod_assign_external::save_submission_parameters();
1659 $this->assertTrue(isset($parameters->keys['plugindata']->keys['files_filemanager']));
1660 $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['files_filemanager']->required);
1661
1662 // Hide feedback file submissiong plugin.
1663 $pluginmanager = new assign_plugin_manager('assignfeedback');
1664 $pluginmanager->hide_plugin('file');
1665
1666 $parameters = mod_assign_external::save_grade_parameters();
1667
1668 $this->assertTrue(!isset($parameters->keys['plugindata']->keys['files_filemanager']));
1669
1670 // Show it again and check that the value is returned as optional.
1671 $pluginmanager->show_plugin('file');
1672 $parameters = mod_assign_external::save_grade_parameters();
1673
1674 $this->assertTrue(isset($parameters->keys['plugindata']->keys['files_filemanager']));
1675 $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['files_filemanager']->required);
1676
1677 // Check a different one.
1678 $pluginmanager->show_plugin('comments');
1679 $this->assertTrue(isset($parameters->keys['plugindata']->keys['assignfeedbackcomments_editor']));
1680 $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['assignfeedbackcomments_editor']->required);
1681 }
1682
e3e036ee
JL
1683 /**
1684 * Test test_view_submission_status
1685 */
1686 public function test_view_submission_status() {
1687 global $DB;
1688
1689 $this->resetAfterTest(true);
1690
1691 $this->setAdminUser();
1692 // Setup test data.
1693 $course = $this->getDataGenerator()->create_course();
1694 $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1695 $context = context_module::instance($assign->cmid);
1696 $cm = get_coursemodule_from_instance('assign', $assign->id);
1697
1698 // Test invalid instance id.
1699 try {
1700 mod_assign_external::view_submission_status(0);
1701 $this->fail('Exception expected due to invalid mod_assign instance id.');
1702 } catch (moodle_exception $e) {
1703 $this->assertEquals('invalidrecord', $e->errorcode);
1704 }
1705
1706 // Test not-enrolled user.
1707 $user = self::getDataGenerator()->create_user();
1708 $this->setUser($user);
1709 try {
1710 mod_assign_external::view_submission_status($assign->id);
1711 $this->fail('Exception expected due to not enrolled user.');
1712 } catch (moodle_exception $e) {
1713 $this->assertEquals('requireloginerror', $e->errorcode);
1714 }
1715
1716 // Test user with full capabilities.
1717 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1718 $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
1719
1720 // Trigger and capture the event.
1721 $sink = $this->redirectEvents();
1722
1723 $result = mod_assign_external::view_submission_status($assign->id);
1724 $result = external_api::clean_returnvalue(mod_assign_external::view_submission_status_returns(), $result);
1725
1726 $events = $sink->get_events();
1727 $this->assertCount(1, $events);
1728 $event = array_shift($events);
1729
1730 // Checking that the event contains the expected values.
1731 $this->assertInstanceOf('\mod_assign\event\submission_status_viewed', $event);
1732 $this->assertEquals($context, $event->get_context());
1733 $moodleurl = new \moodle_url('/mod/assign/view.php', array('id' => $cm->id));
1734 $this->assertEquals($moodleurl, $event->get_url());
1735 $this->assertEventContextNotUsed($event);
1736 $this->assertNotEmpty($event->get_name());
1737
1738 // Test user with no capabilities.
1739 // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
1740 assign_capability('mod/assign:view', CAP_PROHIBIT, $studentrole->id, $context->id);
1741 accesslib_clear_all_caches_for_unit_testing();
1742 course_modinfo::clear_instance_cache();
1743
1744 try {
1745 mod_assign_external::view_submission_status($assign->id);
1746 $this->fail('Exception expected due to missing capability.');
1747 } catch (moodle_exception $e) {
1748 $this->assertEquals('requireloginerror', $e->errorcode);
1749 }
e3e036ee
JL
1750 }
1751
bdf1ac27
JL
1752 /**
1753 * Create a submission for testing the get_submission_status function.
1754 * @param boolean $submitforgrading whether to submit for grading the submission
1755 * @return array an array containing all the required data for testing
1756 */
1757 private function create_submission_for_testing_status($submitforgrading = false) {
1758 global $DB, $CFG;
1759 require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
1760
1761 // Create a course and assignment and users.
1762 $course = self::getDataGenerator()->create_course();
1763
1764 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1765 $params = array(
1766 'course' => $course->id,
1767 'assignsubmission_file_maxfiles' => 1,
1768 'assignsubmission_file_maxsizebytes' => 1024 * 1024,
1769 'assignsubmission_onlinetext_enabled' => 1,
1770 'assignsubmission_file_enabled' => 1,
1771 'submissiondrafts' => 1,
1772 'assignfeedback_file_enabled' => 1,
1773 'assignfeedback_comments_enabled' => 1,
1774 'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
1775 'sendnotifications' => 0
1776 );
1777
1778 set_config('submissionreceipts', 0, 'assign');
1779
1780 $instance = $generator->create_instance($params);
1781 $cm = get_coursemodule_from_instance('assign', $instance->id);
1782 $context = context_module::instance($cm->id);
1783
1784 $assign = new testable_assign($context, $cm, $course);
1785
1786 $student1 = self::getDataGenerator()->create_user();
1787 $student2 = self::getDataGenerator()->create_user();
1788 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1789 $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
1790 $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id);
1791 $teacher = self::getDataGenerator()->create_user();
1792 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1793 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
1794
1795 $this->setUser($student1);
1796
1797 // Create a student1 with an online text submission.
1798 // Simulate a submission.
1799 $submission = $assign->get_user_submission($student1->id, true);
1800
1801 $data = new stdClass();
1802 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1803 'text' => 'Submission text',
1804 'format' => FORMAT_MOODLE);
1805
1806 $draftidfile = file_get_unused_draft_itemid();
1807 $usercontext = context_user::instance($student1->id);
1808 $filerecord = array(
1809 'contextid' => $usercontext->id,
1810 'component' => 'user',
1811 'filearea' => 'draft',
1812 'itemid' => $draftidfile,
1813 'filepath' => '/',
1814 'filename' => 't.txt',
1815 );
1816 $fs = get_file_storage();
1817 $fs->create_file_from_string($filerecord, 'text contents');
1818
1819 $data->files_filemanager = $draftidfile;
1820
1821 $notices = array();
1822 $assign->save_submission($data, $notices);
1823
1824 if ($submitforgrading) {
1825 // Now, submit the draft for grading.
1826 $notices = array();
1827
1828 $data = new stdClass;
1829 $data->userid = $student1->id;
1830 $assign->submit_for_grading($data, $notices);
1831 }
1832
1833 return array($assign, $instance, $student1, $student2, $teacher);
1834 }
1835
1836 /**
1837 * Test get_submission_status for a draft submission.
1838 */
1839 public function test_get_submission_status_in_draft_status() {
1840 $this->resetAfterTest(true);
1841
1842 list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status();
1843
1844 $result = mod_assign_external::get_submission_status($assign->get_instance()->id);
1845 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request.
1846 $this->assertDebuggingCalled();
1847
1848 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result);
1849
1850 // The submission is now in draft mode.
1851 $this->assertCount(0, $result['warnings']);
1852 $this->assertFalse(isset($result['gradingsummary']));
1853 $this->assertFalse(isset($result['feedback']));
1854 $this->assertFalse(isset($result['previousattempts']));
1855
1856 $this->assertTrue($result['lastattempt']['submissionsenabled']);
1857 $this->assertTrue($result['lastattempt']['canedit']);
1858 $this->assertTrue($result['lastattempt']['cansubmit']);
1859 $this->assertFalse($result['lastattempt']['locked']);
1860 $this->assertFalse($result['lastattempt']['graded']);
1861 $this->assertEmpty($result['lastattempt']['extensionduedate']);
1862 $this->assertFalse($result['lastattempt']['blindmarking']);
1863 $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']);
1864 $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']);
1865
1866 $this->assertEquals($student1->id, $result['lastattempt']['submission']['userid']);
1867 $this->assertEquals(0, $result['lastattempt']['submission']['attemptnumber']);
1868 $this->assertEquals('draft', $result['lastattempt']['submission']['status']);
1869 $this->assertEquals(0, $result['lastattempt']['submission']['groupid']);
1870 $this->assertEquals($assign->get_instance()->id, $result['lastattempt']['submission']['assignment']);
1871 $this->assertEquals(1, $result['lastattempt']['submission']['latest']);
11ee4f71
AO
1872
1873 // Map plugins based on their type - we can't rely on them being in a
1874 // particular order, especially if 3rd party plugins are installed.
1875 $submissionplugins = array();
1876 foreach ($result['lastattempt']['submission']['plugins'] as $plugin) {
1877 $submissionplugins[$plugin['type']] = $plugin;
1878 }
1879 $this->assertEquals('Submission text', $submissionplugins['onlinetext']['editorfields'][0]['text']);
1880 $this->assertEquals('/t.txt', $submissionplugins['file']['fileareas'][0]['files'][0]['filepath']);
bdf1ac27
JL
1881 }
1882
1883 /**
1884 * Test get_submission_status for a submitted submission.
1885 */
1886 public function test_get_submission_status_in_submission_status() {
1887 $this->resetAfterTest(true);
1888
1889 list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status(true);
1890
1891 $result = mod_assign_external::get_submission_status($assign->get_instance()->id);
1892 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request.
1893 $this->assertDebuggingCalled();
1894 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result);
1895
1896 $this->assertCount(0, $result['warnings']);
1897 $this->assertFalse(isset($result['gradingsummary']));
1898 $this->assertFalse(isset($result['feedback']));
1899 $this->assertFalse(isset($result['previousattempts']));
1900
1901 $this->assertTrue($result['lastattempt']['submissionsenabled']);
1902 $this->assertFalse($result['lastattempt']['canedit']);
1903 $this->assertFalse($result['lastattempt']['cansubmit']);
1904 $this->assertFalse($result['lastattempt']['locked']);
1905 $this->assertFalse($result['lastattempt']['graded']);
1906 $this->assertEmpty($result['lastattempt']['extensionduedate']);
1907 $this->assertFalse($result['lastattempt']['blindmarking']);
1908 $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']);
1909 $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']);
1910
1911 }
1912
1913 /**
1914 * Test get_submission_status using the teacher role.
1915 */
1916 public function test_get_submission_status_in_submission_status_for_teacher() {
1917 $this->resetAfterTest(true);
1918
1919 list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status(true);
1920
1921 // Now, as teacher, see the grading summary.
1922 $this->setUser($teacher);
1923 $result = mod_assign_external::get_submission_status($assign->get_instance()->id);
1924 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request.
1925 $this->assertDebuggingCalled();
1926 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result);
1927
1928 $this->assertCount(0, $result['warnings']);
1929 $this->assertFalse(isset($result['lastattempt']));
1930 $this->assertFalse(isset($result['feedback']));
1931 $this->assertFalse(isset($result['previousattempts']));
1932
1933 $this->assertEquals(2, $result['gradingsummary']['participantcount']);
1934 $this->assertEquals(0, $result['gradingsummary']['submissiondraftscount']);
1935 $this->assertEquals(1, $result['gradingsummary']['submissionsenabled']);
1936 $this->assertEquals(1, $result['gradingsummary']['submissionssubmittedcount']);
1937 $this->assertEquals(1, $result['gradingsummary']['submissionsneedgradingcount']);
1938 $this->assertFalse($result['gradingsummary']['warnofungroupedusers']);
1939 }
1940
1941 /**
1942 * Test get_submission_status for a reopened submission.
1943 */
1944 public function test_get_submission_status_in_reopened_status() {
1945 global $USER;
1946
1947 $this->resetAfterTest(true);
1948
1949 list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status(true);
1950
1951 $this->setUser($teacher);
1952 // Grade and reopen.
1953 $feedbackpluginparams = array();
1954 $feedbackpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
1955 $feedbackeditorparams = array('text' => 'Yeeha!',
1956 'format' => 1);
1957 $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1958 $result = mod_assign_external::save_grade($instance->id,
1959 $student1->id,
1960 50.0,
1961 -1,
1962 false,
1963 'released',
1964 false,
1965 $feedbackpluginparams);
1966 $USER->ignoresesskey = true;
1967 $assign->testable_process_add_attempt($student1->id);
1968
1969 $this->setUser($student1);
1970
1971 $result = mod_assign_external::get_submission_status($assign->get_instance()->id);
1972 // We expect debugging because of the $PAGE object, this won't happen in a normal WS request.
1973 $this->assertDebuggingCalled();
1974 $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result);
1975
1976 $this->assertCount(0, $result['warnings']);
1977 $this->assertFalse(isset($result['gradingsummary']));
1978
1979 $this->assertTrue($result['lastattempt']['submissionsenabled']);
1980 $this->assertTrue($result['lastattempt']['canedit']);
1981 $this->assertFalse($result['lastattempt']['cansubmit']);
1982 $this->assertFalse($result['lastattempt']['locked']);
1983 $this->assertFalse($result['lastattempt']['graded']);
1984 $this->assertEmpty($result['lastattempt']['extensionduedate']);
1985 $this->assertFalse($result['lastattempt']['blindmarking']);
1986 $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']);
1987 $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']);
1988
1989 // Check new attempt reopened.
1990 $this->assertEquals($student1->id, $result['lastattempt']['submission']['userid']);
1991 $this->assertEquals(1, $result['lastattempt']['submission']['attemptnumber']);
1992 $this->assertEquals('reopened', $result['lastattempt']['submission']['status']);
1993 $this->assertEquals(0, $result['lastattempt']['submission']['groupid']);
1994 $this->assertEquals($assign->get_instance()->id, $result['lastattempt']['submission']['assignment']);
1995 $this->assertEquals(1, $result['lastattempt']['submission']['latest']);
1996 $this->assertCount(3, $result['lastattempt']['submission']['plugins']);
1997
1998 // Now see feedback and the attempts history (remember, is a submission reopened).
1999 // Only 2 fields (no grade, no plugins data).
2000 $this->assertCount(2, $result['feedback']);
2001
2002 // One previous attempt.
2003 $this->assertCount(1, $result['previousattempts']);
2004 $this->assertEquals(0, $result['previousattempts'][0]['attemptnumber']);
2005 $this->assertEquals(50, $result['previousattempts'][0]['grade']['grade']);
2006 $this->assertEquals($teacher->id, $result['previousattempts'][0]['grade']['grader']);
2007 $this->assertEquals($student1->id, $result['previousattempts'][0]['grade']['userid']);
11ee4f71
AO
2008
2009 // Map plugins based on their type - we can't rely on them being in a
2010 // particular order, especially if 3rd party plugins are installed.
2011 $feedbackplugins = array();
2012 foreach ($result['previousattempts'][0]['feedbackplugins'] as $plugin) {
2013 $feedbackplugins[$plugin['type']] = $plugin;
2014 }
2015 $this->assertEquals('Yeeha!', $feedbackplugins['comments']['editorfields'][0]['text']);
2016
2017 $submissionplugins = array();
2018 foreach ($result['previousattempts'][0]['submission']['plugins'] as $plugin) {
2019 $submissionplugins[$plugin['type']] = $plugin;
2020 }
2021 $this->assertEquals('Submission text', $submissionplugins['onlinetext']['editorfields'][0]['text']);
2022 $this->assertEquals('/t.txt', $submissionplugins['file']['fileareas'][0]['files'][0]['filepath']);
bdf1ac27
JL
2023 }
2024
2025 /**
2026 * Test access control for get_submission_status.
2027 */
2028 public function test_get_submission_status_access_control() {
2029 $this->resetAfterTest(true);
2030
2031 list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status();
2032
2033 $this->setUser($student2);
2034
2035 // Access control test.
2036 $this->setExpectedException('required_capability_exception');
2037 mod_assign_external::get_submission_status($assign->get_instance()->id, $student1->id);
2038
2039 }
1f8c8f61 2040}