0dd6de1c140564ce4c539ce55ba67797d7ee6975
[moodle.git] / mod / assign / tests / externallib_test.php
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/>.
17 defined('MOODLE_INTERNAL') || die();
19 global $CFG;
21 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
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  */
31 class mod_assign_external_testcase extends externallib_advanced_testcase {
33     /**
34      * Tests set up
35      */
36     protected function setUp() {
37         global $CFG;
38         require_once($CFG->dirroot . '/mod/assign/externallib.php');
39     }
41     /**
42      * Test get_grades
43      */
44     public function test_get_grades() {
45         global $DB, $USER;
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);
55         $assigndata['course'] = $course->id;
56         $assigndata['name'] = 'lightwork assignment';
58         $assign = self::getDataGenerator()->create_module('assign', $assigndata);
60         // Create a manual enrolment record.
61         $manualenroldata['enrol'] = 'manual';
62         $manualenroldata['status'] = 0;
63         $manualenroldata['courseid'] = $course->id;
64         $enrolid = $DB->insert_record('enrol', $manualenroldata);
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);
69         $context = context_module::instance($assign->cmid);
70         $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
72         // Create the teacher's enrolment record.
73         $userenrolmentdata['status'] = 0;
74         $userenrolmentdata['enrolid'] = $enrolid;
75         $userenrolmentdata['userid'] = $USER->id;
76         $DB->insert_record('user_enrolments', $userenrolmentdata);
78         // Create a student and give them 2 grades (for 2 attempts).
79         $student = self::getDataGenerator()->create_user();
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);
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;
99         $grade->attemptnumber = 0;
100         $DB->insert_record('assign_grades', $grade);
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);
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;
120         $grade->attemptnumber = 1;
121         $DB->insert_record('assign_grades', $grade);
123         $assignmentids[] = $assign->id;
124         $result = mod_assign_external::get_grades($assignmentids);
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);
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']);
133         // Should only get the last grade for this student.
134         $this->assertEquals(1, count($assignment['grades']));
135         $grade = $assignment['grades'][0];
136         $this->assertEquals($student->id, $grade['userid']);
137         // Should be the last grade (not the first).
138         $this->assertEquals(75, $grade['grade']);
139     }
141     /**
142      * Test get_assignments
143      */
144     public function test_get_assignments() {
145         global $DB, $USER;
147         $this->resetAfterTest(true);
149         $category = self::getDataGenerator()->create_category(array(
150             'name' => 'Test category'
151         ));
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         ));
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         ));
171         // Create the assignment module.
172         $assign1 = self::getDataGenerator()->create_module('assign', array(
173             'course' => $course1->id,
174             'name' => 'lightwork assignment',
175             'intro' => 'the assignment intro text here',
176             'markingworkflow' => 1,
177             'markingallocation' => 1
178         ));
180         // Create manual enrolment record.
181         $enrolid = $DB->insert_record('enrol', (object)array(
182             'enrol' => 'manual',
183             'status' => 0,
184             'courseid' => $course1->id
185         ));
187         // Create the user and give them capabilities.
188         $context = context_course::instance($course1->id);
189         $roleid = $this->assignUserCapability('moodle/course:view', $context->id);
190         $context = context_module::instance($assign1->cmid);
191         $this->assignUserCapability('mod/assign:view', $context->id, $roleid);
193         // Create the user enrolment record.
194         $DB->insert_record('user_enrolments', (object)array(
195             'status' => 0,
196             'enrolid' => $enrolid,
197             'userid' => $USER->id
198         ));
200         // Add a file as assignment attachment.
201         $filerecord = array('component' => 'mod_assign', 'filearea' => ASSIGN_INTROATTACHMENT_FILEAREA,
202                 'contextid' => $context->id, 'itemid' => 0,
203                 'filename' => 'introattachment.txt', 'filepath' => '/');
204         $fs = get_file_storage();
205         $fs->create_file_from_string($filerecord, 'Test intro attachment file');
207         $result = mod_assign_external::get_assignments();
209         // We need to execute the return values cleaning process to simulate the web service server.
210         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
212         // Check the course and assignment are returned.
213         $this->assertEquals(1, count($result['courses']));
214         $course = $result['courses'][0];
215         $this->assertEquals('Lightwork Course 1', $course['fullname']);
216         $this->assertEquals(1, count($course['assignments']));
217         $assignment = $course['assignments'][0];
218         $this->assertEquals($assign1->id, $assignment['id']);
219         $this->assertEquals($course1->id, $assignment['course']);
220         $this->assertEquals('lightwork assignment', $assignment['name']);
221         $this->assertEquals('the assignment intro text here', $assignment['intro']);
222         $this->assertEquals(1, $assignment['markingworkflow']);
223         $this->assertEquals(1, $assignment['markingallocation']);
225         $this->assertCount(1, $assignment['introattachments']);
226         $this->assertEquals('introattachment.txt', $assignment['introattachments'][0]['filename']);
228         // Now, hide the descritption until the submission from date.
229         $DB->set_field('assign', 'alwaysshowdescription', 0, array('id' => $assign1->id));
230         $DB->set_field('assign', 'allowsubmissionsfromdate', time() + DAYSECS, array('id' => $assign1->id));
232         $result = mod_assign_external::get_assignments(array($course1->id));
234         // We need to execute the return values cleaning process to simulate the web service server.
235         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
237         $this->assertEquals(1, count($result['courses']));
238         $course = $result['courses'][0];
239         $this->assertEquals('Lightwork Course 1', $course['fullname']);
240         $this->assertEquals(1, count($course['assignments']));
241         $assignment = $course['assignments'][0];
242         $this->assertEquals($assign1->id, $assignment['id']);
243         $this->assertEquals($course1->id, $assignment['course']);
244         $this->assertEquals('lightwork assignment', $assignment['name']);
245         $this->assertArrayNotHasKey('intro', $assignment);
246         $this->assertArrayNotHasKey('introattachments', $assignment);
247         $this->assertEquals(1, $assignment['markingworkflow']);
248         $this->assertEquals(1, $assignment['markingallocation']);
250         $result = mod_assign_external::get_assignments(array($course2->id));
252         // We need to execute the return values cleaning process to simulate the web service server.
253         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
255         $this->assertEquals(0, count($result['courses']));
256         $this->assertEquals(1, count($result['warnings']));
257     }
259     /**
260      * Test get_submissions
261      */
262     public function test_get_submissions() {
263         global $DB, $USER;
265         $this->resetAfterTest(true);
266         // Create a course and assignment.
267         $coursedata['idnumber'] = 'idnumbercourse1';
268         $coursedata['fullname'] = 'Lightwork Course 1';
269         $coursedata['summary'] = 'Lightwork Course 1 description';
270         $coursedata['summaryformat'] = FORMAT_MOODLE;
271         $course1 = self::getDataGenerator()->create_course($coursedata);
273         $assigndata['course'] = $course1->id;
274         $assigndata['name'] = 'lightwork assignment';
276         $assign1 = self::getDataGenerator()->create_module('assign', $assigndata);
278         // Create a student with an online text submission.
279         // First attempt.
280         $student = self::getDataGenerator()->create_user();
281         $submission = new stdClass();
282         $submission->assignment = $assign1->id;
283         $submission->userid = $student->id;
284         $submission->timecreated = time();
285         $submission->timemodified = $submission->timecreated;
286         $submission->status = 'draft';
287         $submission->attemptnumber = 0;
288         $submission->latest = 0;
289         $sid = $DB->insert_record('assign_submission', $submission);
291         // Second attempt.
292         $submission = new stdClass();
293         $submission->assignment = $assign1->id;
294         $submission->userid = $student->id;
295         $submission->timecreated = time();
296         $submission->timemodified = $submission->timecreated;
297         $submission->status = 'submitted';
298         $submission->attemptnumber = 1;
299         $submission->latest = 1;
300         $sid = $DB->insert_record('assign_submission', $submission);
301         $submission->id = $sid;
303         $onlinetextsubmission = new stdClass();
304         $onlinetextsubmission->onlinetext = "<p>online test text</p>";
305         $onlinetextsubmission->onlineformat = 1;
306         $onlinetextsubmission->submission = $submission->id;
307         $onlinetextsubmission->assignment = $assign1->id;
308         $DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission);
310         // Create manual enrolment record.
311         $manualenroldata['enrol'] = 'manual';
312         $manualenroldata['status'] = 0;
313         $manualenroldata['courseid'] = $course1->id;
314         $enrolid = $DB->insert_record('enrol', $manualenroldata);
316         // Create a teacher and give them capabilities.
317         $context = context_course::instance($course1->id);
318         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
319         $context = context_module::instance($assign1->cmid);
320         $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
322         // Create the teacher's enrolment record.
323         $userenrolmentdata['status'] = 0;
324         $userenrolmentdata['enrolid'] = $enrolid;
325         $userenrolmentdata['userid'] = $USER->id;
326         $DB->insert_record('user_enrolments', $userenrolmentdata);
328         $assignmentids[] = $assign1->id;
329         $result = mod_assign_external::get_submissions($assignmentids);
330         $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result);
332         // Check the online text submission is returned.
333         $this->assertEquals(1, count($result['assignments']));
334         $assignment = $result['assignments'][0];
335         $this->assertEquals($assign1->id, $assignment['assignmentid']);
336         $this->assertEquals(1, count($assignment['submissions']));
337         $submission = $assignment['submissions'][0];
338         $this->assertEquals($sid, $submission['id']);
339         $this->assertGreaterThanOrEqual(3, count($submission['plugins']));
340         $plugins = $submission['plugins'];
341         foreach ($plugins as $plugin) {
342             $foundonlinetext = false;
343             if ($plugin['type'] == 'onlinetext') {
344                 $foundonlinetext = true;
345                 break;
346             }
347         }
348         $this->assertTrue($foundonlinetext);
349     }
351     /**
352      * Test get_user_flags
353      */
354     public function test_get_user_flags() {
355         global $DB, $USER;
357         $this->resetAfterTest(true);
358         // Create a course and assignment.
359         $coursedata['idnumber'] = 'idnumbercourse';
360         $coursedata['fullname'] = 'Lightwork Course';
361         $coursedata['summary'] = 'Lightwork Course description';
362         $coursedata['summaryformat'] = FORMAT_MOODLE;
363         $course = self::getDataGenerator()->create_course($coursedata);
365         $assigndata['course'] = $course->id;
366         $assigndata['name'] = 'lightwork assignment';
368         $assign = self::getDataGenerator()->create_module('assign', $assigndata);
370         // Create a manual enrolment record.
371         $manualenroldata['enrol'] = 'manual';
372         $manualenroldata['status'] = 0;
373         $manualenroldata['courseid'] = $course->id;
374         $enrolid = $DB->insert_record('enrol', $manualenroldata);
376         // Create a teacher and give them capabilities.
377         $context = context_course::instance($course->id);
378         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
379         $context = context_module::instance($assign->cmid);
380         $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
382         // Create the teacher's enrolment record.
383         $userenrolmentdata['status'] = 0;
384         $userenrolmentdata['enrolid'] = $enrolid;
385         $userenrolmentdata['userid'] = $USER->id;
386         $DB->insert_record('user_enrolments', $userenrolmentdata);
388         // Create a student and give them a user flag record.
389         $student = self::getDataGenerator()->create_user();
390         $userflag = new stdClass();
391         $userflag->assignment = $assign->id;
392         $userflag->userid = $student->id;
393         $userflag->locked = 0;
394         $userflag->mailed = 0;
395         $userflag->extensionduedate = 0;
396         $userflag->workflowstate = 'inmarking';
397         $userflag->allocatedmarker = $USER->id;
399         $DB->insert_record('assign_user_flags', $userflag);
401         $assignmentids[] = $assign->id;
402         $result = mod_assign_external::get_user_flags($assignmentids);
404         // We need to execute the return values cleaning process to simulate the web service server.
405         $result = external_api::clean_returnvalue(mod_assign_external::get_user_flags_returns(), $result);
407         // Check that the correct user flag information for the student is returned.
408         $this->assertEquals(1, count($result['assignments']));
409         $assignment = $result['assignments'][0];
410         $this->assertEquals($assign->id, $assignment['assignmentid']);
411         // Should be one user flag record.
412         $this->assertEquals(1, count($assignment['userflags']));
413         $userflag = $assignment['userflags'][0];
414         $this->assertEquals($student->id, $userflag['userid']);
415         $this->assertEquals(0, $userflag['locked']);
416         $this->assertEquals(0, $userflag['mailed']);
417         $this->assertEquals(0, $userflag['extensionduedate']);
418         $this->assertEquals('inmarking', $userflag['workflowstate']);
419         $this->assertEquals($USER->id, $userflag['allocatedmarker']);
420     }
422     /**
423      * Test get_user_mappings
424      */
425     public function test_get_user_mappings() {
426         global $DB, $USER;
428         $this->resetAfterTest(true);
429         // Create a course and assignment.
430         $coursedata['idnumber'] = 'idnumbercourse';
431         $coursedata['fullname'] = 'Lightwork Course';
432         $coursedata['summary'] = 'Lightwork Course description';
433         $coursedata['summaryformat'] = FORMAT_MOODLE;
434         $course = self::getDataGenerator()->create_course($coursedata);
436         $assigndata['course'] = $course->id;
437         $assigndata['name'] = 'lightwork assignment';
439         $assign = self::getDataGenerator()->create_module('assign', $assigndata);
441         // Create a manual enrolment record.
442         $manualenroldata['enrol'] = 'manual';
443         $manualenroldata['status'] = 0;
444         $manualenroldata['courseid'] = $course->id;
445         $enrolid = $DB->insert_record('enrol', $manualenroldata);
447         // Create a teacher and give them capabilities.
448         $context = context_course::instance($course->id);
449         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
450         $context = context_module::instance($assign->cmid);
451         $this->assignUserCapability('mod/assign:revealidentities', $context->id, $roleid);
453         // Create the teacher's enrolment record.
454         $userenrolmentdata['status'] = 0;
455         $userenrolmentdata['enrolid'] = $enrolid;
456         $userenrolmentdata['userid'] = $USER->id;
457         $DB->insert_record('user_enrolments', $userenrolmentdata);
459         // Create a student and give them a user mapping record.
460         $student = self::getDataGenerator()->create_user();
461         $mapping = new stdClass();
462         $mapping->assignment = $assign->id;
463         $mapping->userid = $student->id;
465         $DB->insert_record('assign_user_mapping', $mapping);
467         $assignmentids[] = $assign->id;
468         $result = mod_assign_external::get_user_mappings($assignmentids);
470         // We need to execute the return values cleaning process to simulate the web service server.
471         $result = external_api::clean_returnvalue(mod_assign_external::get_user_mappings_returns(), $result);
473         // Check that the correct user mapping information for the student is returned.
474         $this->assertEquals(1, count($result['assignments']));
475         $assignment = $result['assignments'][0];
476         $this->assertEquals($assign->id, $assignment['assignmentid']);
477         // Should be one user mapping record.
478         $this->assertEquals(1, count($assignment['mappings']));
479         $mapping = $assignment['mappings'][0];
480         $this->assertEquals($student->id, $mapping['userid']);
481     }
483     /**
484      * Test lock_submissions
485      */
486     public function test_lock_submissions() {
487         global $DB, $USER;
489         $this->resetAfterTest(true);
490         // Create a course and assignment and users.
491         $course = self::getDataGenerator()->create_course();
493         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
494         $params['course'] = $course->id;
495         $params['assignsubmission_onlinetext_enabled'] = 1;
496         $instance = $generator->create_instance($params);
497         $cm = get_coursemodule_from_instance('assign', $instance->id);
498         $context = context_module::instance($cm->id);
500         $assign = new assign($context, $cm, $course);
502         $student1 = self::getDataGenerator()->create_user();
503         $student2 = self::getDataGenerator()->create_user();
504         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
505         $this->getDataGenerator()->enrol_user($student1->id,
506                                               $course->id,
507                                               $studentrole->id);
508         $this->getDataGenerator()->enrol_user($student2->id,
509                                               $course->id,
510                                               $studentrole->id);
511         $teacher = self::getDataGenerator()->create_user();
512         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
513         $this->getDataGenerator()->enrol_user($teacher->id,
514                                               $course->id,
515                                               $teacherrole->id);
517         // Create a student1 with an online text submission.
518         // Simulate a submission.
519         $this->setUser($student1);
520         $submission = $assign->get_user_submission($student1->id, true);
521         $data = new stdClass();
522         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
523                                          'text'=>'Submission text',
524                                          'format'=>FORMAT_MOODLE);
525         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
526         $plugin->save($submission, $data);
528         // Ready to test.
529         $this->setUser($teacher);
530         $students = array($student1->id, $student2->id);
531         $result = mod_assign_external::lock_submissions($instance->id, $students);
532         $result = external_api::clean_returnvalue(mod_assign_external::lock_submissions_returns(), $result);
534         // Check for 0 warnings.
535         $this->assertEquals(0, count($result));
537         $this->setUser($student2);
538         $submission = $assign->get_user_submission($student2->id, true);
539         $data = new stdClass();
540         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
541                                          'text'=>'Submission text',
542                                          'format'=>FORMAT_MOODLE);
543         $notices = array();
544         $this->setExpectedException('moodle_exception');
545         $assign->save_submission($data, $notices);
546     }
548     /**
549      * Test unlock_submissions
550      */
551     public function test_unlock_submissions() {
552         global $DB, $USER;
554         $this->resetAfterTest(true);
555         // Create a course and assignment and users.
556         $course = self::getDataGenerator()->create_course();
558         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
559         $params['course'] = $course->id;
560         $params['assignsubmission_onlinetext_enabled'] = 1;
561         $instance = $generator->create_instance($params);
562         $cm = get_coursemodule_from_instance('assign', $instance->id);
563         $context = context_module::instance($cm->id);
565         $assign = new assign($context, $cm, $course);
567         $student1 = self::getDataGenerator()->create_user();
568         $student2 = self::getDataGenerator()->create_user();
569         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
570         $this->getDataGenerator()->enrol_user($student1->id,
571                                               $course->id,
572                                               $studentrole->id);
573         $this->getDataGenerator()->enrol_user($student2->id,
574                                               $course->id,
575                                               $studentrole->id);
576         $teacher = self::getDataGenerator()->create_user();
577         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
578         $this->getDataGenerator()->enrol_user($teacher->id,
579                                               $course->id,
580                                               $teacherrole->id);
582         // Create a student1 with an online text submission.
583         // Simulate a submission.
584         $this->setUser($student1);
585         $submission = $assign->get_user_submission($student1->id, true);
586         $data = new stdClass();
587         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
588                                          'text'=>'Submission text',
589                                          'format'=>FORMAT_MOODLE);
590         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
591         $plugin->save($submission, $data);
593         // Ready to test.
594         $this->setUser($teacher);
595         $students = array($student1->id, $student2->id);
596         $result = mod_assign_external::lock_submissions($instance->id, $students);
597         $result = external_api::clean_returnvalue(mod_assign_external::lock_submissions_returns(), $result);
599         // Check for 0 warnings.
600         $this->assertEquals(0, count($result));
602         $result = mod_assign_external::unlock_submissions($instance->id, $students);
603         $result = external_api::clean_returnvalue(mod_assign_external::unlock_submissions_returns(), $result);
605         // Check for 0 warnings.
606         $this->assertEquals(0, count($result));
608         $this->setUser($student2);
609         $submission = $assign->get_user_submission($student2->id, true);
610         $data = new stdClass();
611         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
612                                          'text'=>'Submission text',
613                                          'format'=>FORMAT_MOODLE);
614         $notices = array();
615         $assign->save_submission($data, $notices);
616     }
618     /**
619      * Test submit_for_grading
620      */
621     public function test_submit_for_grading() {
622         global $DB, $USER;
624         $this->resetAfterTest(true);
625         // Create a course and assignment and users.
626         $course = self::getDataGenerator()->create_course();
628         set_config('submissionreceipts', 0, 'assign');
629         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
630         $params['course'] = $course->id;
631         $params['assignsubmission_onlinetext_enabled'] = 1;
632         $params['submissiondrafts'] = 1;
633         $params['sendnotifications'] = 0;
634         $params['requiresubmissionstatement'] = 1;
635         $instance = $generator->create_instance($params);
636         $cm = get_coursemodule_from_instance('assign', $instance->id);
637         $context = context_module::instance($cm->id);
639         $assign = new assign($context, $cm, $course);
641         $student1 = self::getDataGenerator()->create_user();
642         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
643         $this->getDataGenerator()->enrol_user($student1->id,
644                                               $course->id,
645                                               $studentrole->id);
647         // Create a student1 with an online text submission.
648         // Simulate a submission.
649         $this->setUser($student1);
650         $submission = $assign->get_user_submission($student1->id, true);
651         $data = new stdClass();
652         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
653                                          'text'=>'Submission text',
654                                          'format'=>FORMAT_MOODLE);
655         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
656         $plugin->save($submission, $data);
658         $result = mod_assign_external::submit_for_grading($instance->id, false);
659         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
661         // Should be 1 fail because the submission statement was not aceptted.
662         $this->assertEquals(1, count($result));
664         $result = mod_assign_external::submit_for_grading($instance->id, true);
665         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
667         // Check for 0 warnings.
668         $this->assertEquals(0, count($result));
670         $submission = $assign->get_user_submission($student1->id, false);
672         $this->assertEquals(ASSIGN_SUBMISSION_STATUS_SUBMITTED, $submission->status);
673     }
675     /**
676      * Test save_user_extensions
677      */
678     public function test_save_user_extensions() {
679         global $DB, $USER;
681         $this->resetAfterTest(true);
682         // Create a course and assignment and users.
683         $course = self::getDataGenerator()->create_course();
685         $teacher = self::getDataGenerator()->create_user();
686         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
687         $this->getDataGenerator()->enrol_user($teacher->id,
688                                               $course->id,
689                                               $teacherrole->id);
690         $this->setUser($teacher);
692         $now = time();
693         $yesterday = $now - 24*60*60;
694         $tomorrow = $now + 24*60*60;
695         set_config('submissionreceipts', 0, 'assign');
696         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
697         $params['course'] = $course->id;
698         $params['submissiondrafts'] = 1;
699         $params['sendnotifications'] = 0;
700         $params['duedate'] = $yesterday;
701         $params['cutoffdate'] = $now - 10;
702         $instance = $generator->create_instance($params);
703         $cm = get_coursemodule_from_instance('assign', $instance->id);
704         $context = context_module::instance($cm->id);
706         $assign = new assign($context, $cm, $course);
708         $student1 = self::getDataGenerator()->create_user();
709         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
710         $this->getDataGenerator()->enrol_user($student1->id,
711                                               $course->id,
712                                               $studentrole->id);
714         $this->setUser($student1);
715         $result = mod_assign_external::submit_for_grading($instance->id, true);
716         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
718         // Check for 0 warnings.
719         $this->assertEquals(1, count($result));
721         $this->setUser($teacher);
722         $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow));
723         $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
724         $this->assertEquals(1, count($result));
726         $this->setUser($teacher);
727         $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($yesterday - 10));
728         $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
729         $this->assertEquals(1, count($result));
731         $this->setUser($teacher);
732         $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($tomorrow));
733         $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
734         $this->assertEquals(0, count($result));
736         $this->setUser($student1);
737         $result = mod_assign_external::submit_for_grading($instance->id, true);
738         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
739         $this->assertEquals(0, count($result));
741         $this->setUser($student1);
742         $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow));
743         $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
745     }
747     /**
748      * Test reveal_identities
749      */
750     public function test_reveal_identities() {
751         global $DB, $USER;
753         $this->resetAfterTest(true);
754         // Create a course and assignment and users.
755         $course = self::getDataGenerator()->create_course();
757         $teacher = self::getDataGenerator()->create_user();
758         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
759         $this->getDataGenerator()->enrol_user($teacher->id,
760                                               $course->id,
761                                               $teacherrole->id);
762         $this->setUser($teacher);
764         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
765         $params['course'] = $course->id;
766         $params['submissiondrafts'] = 1;
767         $params['sendnotifications'] = 0;
768         $params['blindmarking'] = 1;
769         $instance = $generator->create_instance($params);
770         $cm = get_coursemodule_from_instance('assign', $instance->id);
771         $context = context_module::instance($cm->id);
773         $assign = new assign($context, $cm, $course);
775         $student1 = self::getDataGenerator()->create_user();
776         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
777         $this->getDataGenerator()->enrol_user($student1->id,
778                                               $course->id,
779                                               $studentrole->id);
781         $this->setUser($student1);
782         $this->setExpectedException('required_capability_exception');
783         $result = mod_assign_external::reveal_identities($instance->id);
784         $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
785         $this->assertEquals(1, count($result));
786         $this->assertEquals(true, $assign->is_blind_marking());
788         $this->setUser($teacher);
789         $result = mod_assign_external::reveal_identities($instance->id);
790         $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
791         $this->assertEquals(0, count($result));
792         $this->assertEquals(false, $assign->is_blind_marking());
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'] = 0;
799         $instance = $generator->create_instance($params);
800         $cm = get_coursemodule_from_instance('assign', $instance->id);
801         $context = context_module::instance($cm->id);
803         $assign = new assign($context, $cm, $course);
804         $result = mod_assign_external::reveal_identities($instance->id);
805         $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
806         $this->assertEquals(1, count($result));
807         $this->assertEquals(false, $assign->is_blind_marking());
809     }
811     /**
812      * Test revert_submissions_to_draft
813      */
814     public function test_revert_submissions_to_draft() {
815         global $DB, $USER;
817         $this->resetAfterTest(true);
818         set_config('submissionreceipts', 0, 'assign');
819         // Create a course and assignment and users.
820         $course = self::getDataGenerator()->create_course();
822         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
823         $params['course'] = $course->id;
824         $params['sendnotifications'] = 0;
825         $params['submissiondrafts'] = 1;
826         $instance = $generator->create_instance($params);
827         $cm = get_coursemodule_from_instance('assign', $instance->id);
828         $context = context_module::instance($cm->id);
830         $assign = new assign($context, $cm, $course);
832         $student1 = self::getDataGenerator()->create_user();
833         $student2 = self::getDataGenerator()->create_user();
834         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
835         $this->getDataGenerator()->enrol_user($student1->id,
836                                               $course->id,
837                                               $studentrole->id);
838         $this->getDataGenerator()->enrol_user($student2->id,
839                                               $course->id,
840                                               $studentrole->id);
841         $teacher = self::getDataGenerator()->create_user();
842         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
843         $this->getDataGenerator()->enrol_user($teacher->id,
844                                               $course->id,
845                                               $teacherrole->id);
847         // Create a student1 with an online text submission.
848         // Simulate a submission.
849         $this->setUser($student1);
850         $result = mod_assign_external::submit_for_grading($instance->id, true);
851         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
852         $this->assertEquals(0, count($result));
854         // Ready to test.
855         $this->setUser($teacher);
856         $students = array($student1->id, $student2->id);
857         $result = mod_assign_external::revert_submissions_to_draft($instance->id, array($student1->id));
858         $result = external_api::clean_returnvalue(mod_assign_external::revert_submissions_to_draft_returns(), $result);
860         // Check for 0 warnings.
861         $this->assertEquals(0, count($result));
863     }
865     /**
866      * Test save_submission
867      */
868     public function test_save_submission() {
869         global $DB, $USER;
871         $this->resetAfterTest(true);
872         // Create a course and assignment and users.
873         $course = self::getDataGenerator()->create_course();
875         $teacher = self::getDataGenerator()->create_user();
876         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
877         $this->getDataGenerator()->enrol_user($teacher->id,
878                                               $course->id,
879                                               $teacherrole->id);
880         $this->setUser($teacher);
882         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
883         $params['course'] = $course->id;
884         $params['assignsubmission_onlinetext_enabled'] = 1;
885         $params['assignsubmission_file_enabled'] = 1;
886         $params['assignsubmission_file_maxfiles'] = 5;
887         $params['assignsubmission_file_maxsizebytes'] = 1024*1024;
888         $instance = $generator->create_instance($params);
889         $cm = get_coursemodule_from_instance('assign', $instance->id);
890         $context = context_module::instance($cm->id);
892         $assign = new assign($context, $cm, $course);
894         $student1 = self::getDataGenerator()->create_user();
895         $student2 = self::getDataGenerator()->create_user();
896         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
897         $this->getDataGenerator()->enrol_user($student1->id,
898                                               $course->id,
899                                               $studentrole->id);
900         $this->getDataGenerator()->enrol_user($student2->id,
901                                               $course->id,
902                                               $studentrole->id);
903         // Create a student1 with an online text submission.
904         // Simulate a submission.
905         $this->setUser($student1);
907         // Create a file in a draft area.
908         $draftidfile = file_get_unused_draft_itemid();
910         $usercontext = context_user::instance($student1->id);
911         $filerecord = array(
912             'contextid' => $usercontext->id,
913             'component' => 'user',
914             'filearea'  => 'draft',
915             'itemid'    => $draftidfile,
916             'filepath'  => '/',
917             'filename'  => 'testtext.txt',
918         );
920         $fs = get_file_storage();
921         $fs->create_file_from_string($filerecord, 'text contents');
923         // Create another file in a different draft area.
924         $draftidonlinetext = file_get_unused_draft_itemid();
926         $filerecord = array(
927             'contextid' => $usercontext->id,
928             'component' => 'user',
929             'filearea'  => 'draft',
930             'itemid'    => $draftidonlinetext,
931             'filepath'  => '/',
932             'filename'  => 'shouldbeanimage.txt',
933         );
935         $fs->create_file_from_string($filerecord, 'image contents (not really)');
937         // Now try a submission.
938         $submissionpluginparams = array();
939         $submissionpluginparams['files_filemanager'] = $draftidfile;
940         $onlinetexteditorparams = array('text'=>'Yeeha!',
941                                         'format'=>1,
942                                         'itemid'=>$draftidonlinetext);
943         $submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams;
944         $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
945         $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result);
947         $this->assertEquals(0, count($result));
949     }
951     /**
952      * Test save_grade
953      */
954     public function test_save_grade() {
955         global $DB, $USER;
957         $this->resetAfterTest(true);
958         // Create a course and assignment and users.
959         $course = self::getDataGenerator()->create_course();
961         $teacher = self::getDataGenerator()->create_user();
962         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
963         $this->getDataGenerator()->enrol_user($teacher->id,
964                                               $course->id,
965                                               $teacherrole->id);
966         $this->setUser($teacher);
968         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
969         $params['course'] = $course->id;
970         $params['assignfeedback_file_enabled'] = 1;
971         $params['assignfeedback_comments_enabled'] = 1;
972         $instance = $generator->create_instance($params);
973         $cm = get_coursemodule_from_instance('assign', $instance->id);
974         $context = context_module::instance($cm->id);
976         $assign = new assign($context, $cm, $course);
978         $student1 = self::getDataGenerator()->create_user();
979         $student2 = self::getDataGenerator()->create_user();
980         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
981         $this->getDataGenerator()->enrol_user($student1->id,
982                                               $course->id,
983                                               $studentrole->id);
984         $this->getDataGenerator()->enrol_user($student2->id,
985                                               $course->id,
986                                               $studentrole->id);
987         // Simulate a grade.
988         $this->setUser($teacher);
990         // Create a file in a draft area.
991         $draftidfile = file_get_unused_draft_itemid();
993         $usercontext = context_user::instance($teacher->id);
994         $filerecord = array(
995             'contextid' => $usercontext->id,
996             'component' => 'user',
997             'filearea'  => 'draft',
998             'itemid'    => $draftidfile,
999             'filepath'  => '/',
1000             'filename'  => 'testtext.txt',
1001         );
1003         $fs = get_file_storage();
1004         $fs->create_file_from_string($filerecord, 'text contents');
1006         // Now try a grade.
1007         $feedbackpluginparams = array();
1008         $feedbackpluginparams['files_filemanager'] = $draftidfile;
1009         $feedbackeditorparams = array('text' => 'Yeeha!',
1010                                         'format' => 1);
1011         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1012         $result = mod_assign_external::save_grade($instance->id,
1013                                                   $student1->id,
1014                                                   50.0,
1015                                                   -1,
1016                                                   true,
1017                                                   'released',
1018                                                   false,
1019                                                   $feedbackpluginparams);
1020         // No warnings.
1021         $this->assertNull($result);
1023         $result = mod_assign_external::get_grades(array($instance->id));
1024         $result = external_api::clean_returnvalue(mod_assign_external::get_grades_returns(), $result);
1026         $this->assertEquals($result['assignments'][0]['grades'][0]['grade'], '50.0');
1027     }
1029     /**
1030      * Test save grades with advanced grading data
1031      */
1032     public function test_save_grades_with_advanced_grading() {
1033         global $DB, $USER;
1035         $this->resetAfterTest(true);
1036         // Create a course and assignment and users.
1037         $course = self::getDataGenerator()->create_course();
1039         $teacher = self::getDataGenerator()->create_user();
1040         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1041         $this->getDataGenerator()->enrol_user($teacher->id,
1042                                               $course->id,
1043                                               $teacherrole->id);
1045         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1046         $params['course'] = $course->id;
1047         $params['assignfeedback_file_enabled'] = 0;
1048         $params['assignfeedback_comments_enabled'] = 0;
1049         $instance = $generator->create_instance($params);
1050         $cm = get_coursemodule_from_instance('assign', $instance->id);
1051         $context = context_module::instance($cm->id);
1053         $assign = new assign($context, $cm, $course);
1055         $student1 = self::getDataGenerator()->create_user();
1056         $student2 = self::getDataGenerator()->create_user();
1057         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1058         $this->getDataGenerator()->enrol_user($student1->id,
1059                                               $course->id,
1060                                               $studentrole->id);
1061         $this->getDataGenerator()->enrol_user($student2->id,
1062                                               $course->id,
1063                                               $studentrole->id);
1065         $this->setUser($teacher);
1067         $feedbackpluginparams = array();
1068         $feedbackpluginparams['files_filemanager'] = 0;
1069         $feedbackeditorparams = array('text' => '', 'format' => 1);
1070         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1072         // Create advanced grading data.
1073         // Create grading area.
1074         $gradingarea = array(
1075             'contextid' => $context->id,
1076             'component' => 'mod_assign',
1077             'areaname' => 'submissions',
1078             'activemethod' => 'rubric'
1079         );
1080         $areaid = $DB->insert_record('grading_areas', $gradingarea);
1082         // Create a rubric grading definition.
1083         $rubricdefinition = array (
1084             'areaid' => $areaid,
1085             'method' => 'rubric',
1086             'name' => 'test',
1087             'status' => 20,
1088             'copiedfromid' => 1,
1089             'timecreated' => 1,
1090             'usercreated' => $teacher->id,
1091             'timemodified' => 1,
1092             'usermodified' => $teacher->id,
1093             'timecopied' => 0
1094         );
1095         $definitionid = $DB->insert_record('grading_definitions', $rubricdefinition);
1097         // Create a criterion with a level.
1098         $rubriccriteria = array (
1099              'definitionid' => $definitionid,
1100              'sortorder' => 1,
1101              'description' => 'Demonstrate an understanding of disease control',
1102              'descriptionformat' => 0
1103         );
1104         $criterionid = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria);
1105         $rubriclevel1 = array (
1106             'criterionid' => $criterionid,
1107             'score' => 50,
1108             'definition' => 'pass',
1109             'definitionformat' => 0
1110         );
1111         $rubriclevel2 = array (
1112             'criterionid' => $criterionid,
1113             'score' => 100,
1114             'definition' => 'excellent',
1115             'definitionformat' => 0
1116         );
1117         $rubriclevel3 = array (
1118             'criterionid' => $criterionid,
1119             'score' => 0,
1120             'definition' => 'fail',
1121             'definitionformat' => 0
1122         );
1123         $levelid1 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel1);
1124         $levelid2 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel2);
1125         $levelid3 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel3);
1127         // Create the filling.
1128         $student1filling = array (
1129             'criterionid' => $criterionid,
1130             'levelid' => $levelid1,
1131             'remark' => 'well done you passed',
1132             'remarkformat' => 0
1133         );
1135         $student2filling = array (
1136             'criterionid' => $criterionid,
1137             'levelid' => $levelid2,
1138             'remark' => 'Excellent work',
1139             'remarkformat' => 0
1140         );
1142         $student1criteria = array(array('criterionid' => $criterionid, 'fillings' => array($student1filling)));
1143         $student1advancedgradingdata = array('rubric' => array('criteria' => $student1criteria));
1145         $student2criteria = array(array('criterionid' => $criterionid, 'fillings' => array($student2filling)));
1146         $student2advancedgradingdata = array('rubric' => array('criteria' => $student2criteria));
1148         $grades = array();
1149         $student1gradeinfo = array();
1150         $student1gradeinfo['userid'] = $student1->id;
1151         $student1gradeinfo['grade'] = 0; // Ignored since advanced grading is being used.
1152         $student1gradeinfo['attemptnumber'] = -1;
1153         $student1gradeinfo['addattempt'] = true;
1154         $student1gradeinfo['workflowstate'] = 'released';
1155         $student1gradeinfo['plugindata'] = $feedbackpluginparams;
1156         $student1gradeinfo['advancedgradingdata'] = $student1advancedgradingdata;
1157         $grades[] = $student1gradeinfo;
1159         $student2gradeinfo = array();
1160         $student2gradeinfo['userid'] = $student2->id;
1161         $student2gradeinfo['grade'] = 0; // Ignored since advanced grading is being used.
1162         $student2gradeinfo['attemptnumber'] = -1;
1163         $student2gradeinfo['addattempt'] = true;
1164         $student2gradeinfo['workflowstate'] = 'released';
1165         $student2gradeinfo['plugindata'] = $feedbackpluginparams;
1166         $student2gradeinfo['advancedgradingdata'] = $student2advancedgradingdata;
1167         $grades[] = $student2gradeinfo;
1169         $result = mod_assign_external::save_grades($instance->id, false, $grades);
1170         $this->assertNull($result);
1172         $student1grade = $DB->get_record('assign_grades',
1173                                          array('userid' => $student1->id, 'assignment' => $instance->id),
1174                                          '*',
1175                                          MUST_EXIST);
1176         $this->assertEquals($student1grade->grade, '50.0');
1178         $student2grade = $DB->get_record('assign_grades',
1179                                          array('userid' => $student2->id, 'assignment' => $instance->id),
1180                                          '*',
1181                                          MUST_EXIST);
1182         $this->assertEquals($student2grade->grade, '100.0');
1183     }
1185     /**
1186      * Test save grades for a team submission
1187      */
1188     public function test_save_grades_with_group_submission() {
1189         global $DB, $USER, $CFG;
1190         require_once($CFG->dirroot . '/group/lib.php');
1192         $this->resetAfterTest(true);
1193         // Create a course and assignment and users.
1194         $course = self::getDataGenerator()->create_course();
1196         $teacher = self::getDataGenerator()->create_user();
1197         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1198         $this->getDataGenerator()->enrol_user($teacher->id,
1199                                               $course->id,
1200                                               $teacherrole->id);
1202         $groupingdata = array();
1203         $groupingdata['courseid'] = $course->id;
1204         $groupingdata['name'] = 'Group assignment grouping';
1206         $grouping = self::getDataGenerator()->create_grouping($groupingdata);
1208         $group1data = array();
1209         $group1data['courseid'] = $course->id;
1210         $group1data['name'] = 'Team 1';
1211         $group2data = array();
1212         $group2data['courseid'] = $course->id;
1213         $group2data['name'] = 'Team 2';
1215         $group1 = self::getDataGenerator()->create_group($group1data);
1216         $group2 = self::getDataGenerator()->create_group($group2data);
1218         groups_assign_grouping($grouping->id, $group1->id);
1219         groups_assign_grouping($grouping->id, $group2->id);
1221         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1222         $params['course'] = $course->id;
1223         $params['teamsubmission'] = 1;
1224         $params['teamsubmissiongroupingid'] = $grouping->id;
1225         $instance = $generator->create_instance($params);
1226         $cm = get_coursemodule_from_instance('assign', $instance->id);
1227         $context = context_module::instance($cm->id);
1229         $assign = new assign($context, $cm, $course);
1231         $student1 = self::getDataGenerator()->create_user();
1232         $student2 = self::getDataGenerator()->create_user();
1233         $student3 = self::getDataGenerator()->create_user();
1234         $student4 = self::getDataGenerator()->create_user();
1235         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1236         $this->getDataGenerator()->enrol_user($student1->id,
1237                                               $course->id,
1238                                               $studentrole->id);
1239         $this->getDataGenerator()->enrol_user($student2->id,
1240                                               $course->id,
1241                                               $studentrole->id);
1242         $this->getDataGenerator()->enrol_user($student3->id,
1243                                               $course->id,
1244                                               $studentrole->id);
1245         $this->getDataGenerator()->enrol_user($student4->id,
1246                                               $course->id,
1247                                               $studentrole->id);
1249         groups_add_member($group1->id, $student1->id);
1250         groups_add_member($group1->id, $student2->id);
1251         groups_add_member($group1->id, $student3->id);
1252         groups_add_member($group2->id, $student4->id);
1253         $this->setUser($teacher);
1255         $feedbackpluginparams = array();
1256         $feedbackpluginparams['files_filemanager'] = 0;
1257         $feedbackeditorparams = array('text' => '', 'format' => 1);
1258         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1260         $grades1 = array();
1261         $student1gradeinfo = array();
1262         $student1gradeinfo['userid'] = $student1->id;
1263         $student1gradeinfo['grade'] = 50;
1264         $student1gradeinfo['attemptnumber'] = -1;
1265         $student1gradeinfo['addattempt'] = true;
1266         $student1gradeinfo['workflowstate'] = 'released';
1267         $student1gradeinfo['plugindata'] = $feedbackpluginparams;
1268         $grades1[] = $student1gradeinfo;
1270         $student2gradeinfo = array();
1271         $student2gradeinfo['userid'] = $student2->id;
1272         $student2gradeinfo['grade'] = 75;
1273         $student2gradeinfo['attemptnumber'] = -1;
1274         $student2gradeinfo['addattempt'] = true;
1275         $student2gradeinfo['workflowstate'] = 'released';
1276         $student2gradeinfo['plugindata'] = $feedbackpluginparams;
1277         $grades1[] = $student2gradeinfo;
1279         $this->setExpectedException('invalid_parameter_exception');
1280         // Expect an exception since 2 grades have been submitted for the same team.
1281         $result = mod_assign_external::save_grades($instance->id, true, $grades1);
1282         $result = external_api::clean_returnvalue(mod_assign_external::save_grades_returns(), $result);
1284         $grades2 = array();
1285         $student3gradeinfo = array();
1286         $student3gradeinfo['userid'] = $student3->id;
1287         $student3gradeinfo['grade'] = 50;
1288         $student3gradeinfo['attemptnumber'] = -1;
1289         $student3gradeinfo['addattempt'] = true;
1290         $student3gradeinfo['workflowstate'] = 'released';
1291         $student3gradeinfo['plugindata'] = $feedbackpluginparams;
1292         $grades2[] = $student3gradeinfo;
1294         $student4gradeinfo = array();
1295         $student4gradeinfo['userid'] = $student4->id;
1296         $student4gradeinfo['grade'] = 75;
1297         $student4gradeinfo['attemptnumber'] = -1;
1298         $student4gradeinfo['addattempt'] = true;
1299         $student4gradeinfo['workflowstate'] = 'released';
1300         $student4gradeinfo['plugindata'] = $feedbackpluginparams;
1301         $grades2[] = $student4gradeinfo;
1302         $result = mod_assign_external::save_grades($instance->id, true, $grades2);
1303         $result = external_api::clean_returnvalue(mod_assign_external::save_grades_returns(), $result);
1304         // There should be no warnings.
1305         $this->assertEquals(0, count($result));
1307         $student3grade = $DB->get_record('assign_grades',
1308                                          array('userid' => $student3->id, 'assignment' => $instance->id),
1309                                          '*',
1310                                          MUST_EXIST);
1311         $this->assertEquals($student3grade->grade, '50.0');
1313         $student4grade = $DB->get_record('assign_grades',
1314                                          array('userid' => $student4->id, 'assignment' => $instance->id),
1315                                          '*',
1316                                          MUST_EXIST);
1317         $this->assertEquals($student4grade->grade, '75.0');
1318     }
1320     /**
1321      * Test copy_previous_attempt
1322      */
1323     public function test_copy_previous_attempt() {
1324         global $DB, $USER;
1326         $this->resetAfterTest(true);
1327         // Create a course and assignment and users.
1328         $course = self::getDataGenerator()->create_course();
1330         $teacher = self::getDataGenerator()->create_user();
1331         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
1332         $this->getDataGenerator()->enrol_user($teacher->id,
1333                                               $course->id,
1334                                               $teacherrole->id);
1335         $this->setUser($teacher);
1337         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1338         $params['course'] = $course->id;
1339         $params['assignsubmission_onlinetext_enabled'] = 1;
1340         $params['assignsubmission_file_enabled'] = 0;
1341         $params['assignfeedback_file_enabled'] = 0;
1342         $params['attemptreopenmethod'] = 'manual';
1343         $params['maxattempts'] = 5;
1344         $instance = $generator->create_instance($params);
1345         $cm = get_coursemodule_from_instance('assign', $instance->id);
1346         $context = context_module::instance($cm->id);
1348         $assign = new assign($context, $cm, $course);
1350         $student1 = self::getDataGenerator()->create_user();
1351         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
1352         $this->getDataGenerator()->enrol_user($student1->id,
1353                                               $course->id,
1354                                               $studentrole->id);
1355         // Now try a submission.
1356         $this->setUser($student1);
1357         $draftidonlinetext = file_get_unused_draft_itemid();
1358         $submissionpluginparams = array();
1359         $onlinetexteditorparams = array('text'=>'Yeeha!',
1360                                         'format'=>1,
1361                                         'itemid'=>$draftidonlinetext);
1362         $submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams;
1363         $submissionpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
1364         $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
1365         $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result);
1367         $this->setUser($teacher);
1368         // Add a grade and reopen the attempt.
1369         // Now try a grade.
1370         $feedbackpluginparams = array();
1371         $feedbackpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
1372         $feedbackeditorparams = array('text'=>'Yeeha!',
1373                                         'format'=>1);
1374         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1375         $result = mod_assign_external::save_grade($instance->id,
1376                                                   $student1->id,
1377                                                   50.0,
1378                                                   -1,
1379                                                   true,
1380                                                   'released',
1381                                                   false,
1382                                                   $feedbackpluginparams);
1383         $this->assertNull($result);
1385         $this->setUser($student1);
1386         // Now copy the previous attempt.
1387         $result = mod_assign_external::copy_previous_attempt($instance->id);
1388         $result = external_api::clean_returnvalue(mod_assign_external::copy_previous_attempt_returns(), $result);
1389         // No warnings.
1390         $this->assertEquals(0, count($result));
1392         $this->setUser($teacher);
1393         $result = mod_assign_external::get_submissions(array($instance->id));
1394         $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result);
1396         // Check we are now on the second attempt.
1397         $this->assertEquals($result['assignments'][0]['submissions'][0]['attemptnumber'], 1);
1398         // Check the plugins data is not empty.
1399         $this->assertNotEmpty($result['assignments'][0]['submissions'][0]['plugins']);
1401     }
1403     /**
1404      * Test set_user_flags
1405      */
1406     public function test_set_user_flags() {
1407         global $DB, $USER;
1409         $this->resetAfterTest(true);
1410         // Create a course and assignment.
1411         $coursedata['idnumber'] = 'idnumbercourse';
1412         $coursedata['fullname'] = 'Lightwork Course';
1413         $coursedata['summary'] = 'Lightwork Course description';
1414         $coursedata['summaryformat'] = FORMAT_MOODLE;
1415         $course = self::getDataGenerator()->create_course($coursedata);
1417         $assigndata['course'] = $course->id;
1418         $assigndata['name'] = 'lightwork assignment';
1420         $assign = self::getDataGenerator()->create_module('assign', $assigndata);
1422         // Create a manual enrolment record.
1423         $manualenroldata['enrol'] = 'manual';
1424         $manualenroldata['status'] = 0;
1425         $manualenroldata['courseid'] = $course->id;
1426         $enrolid = $DB->insert_record('enrol', $manualenroldata);
1428         // Create a teacher and give them capabilities.
1429         $context = context_course::instance($course->id);
1430         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
1431         $context = context_module::instance($assign->cmid);
1432         $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
1434         // Create the teacher's enrolment record.
1435         $userenrolmentdata['status'] = 0;
1436         $userenrolmentdata['enrolid'] = $enrolid;
1437         $userenrolmentdata['userid'] = $USER->id;
1438         $DB->insert_record('user_enrolments', $userenrolmentdata);
1440         // Create a student.
1441         $student = self::getDataGenerator()->create_user();
1443         // Create test user flags record.
1444         $userflags = array();
1445         $userflag['userid'] = $student->id;
1446         $userflag['workflowstate'] = 'inmarking';
1447         $userflag['allocatedmarker'] = $USER->id;
1448         $userflags = array($userflag);
1450         $createduserflags = mod_assign_external::set_user_flags($assign->id, $userflags);
1451         // We need to execute the return values cleaning process to simulate the web service server.
1452         $createduserflags = external_api::clean_returnvalue(mod_assign_external::set_user_flags_returns(), $createduserflags);
1454         $this->assertEquals($student->id, $createduserflags[0]['userid']);
1455         $createduserflag = $DB->get_record('assign_user_flags', array('id' => $createduserflags[0]['id']));
1457         // Confirm that all data was inserted correctly.
1458         $this->assertEquals($student->id,  $createduserflag->userid);
1459         $this->assertEquals($assign->id, $createduserflag->assignment);
1460         $this->assertEquals(0, $createduserflag->locked);
1461         $this->assertEquals(2, $createduserflag->mailed);
1462         $this->assertEquals(0, $createduserflag->extensionduedate);
1463         $this->assertEquals('inmarking', $createduserflag->workflowstate);
1464         $this->assertEquals($USER->id, $createduserflag->allocatedmarker);
1466         // Create update data.
1467         $userflags = array();
1468         $userflag['userid'] = $createduserflag->userid;
1469         $userflag['workflowstate'] = 'readyforreview';
1470         $userflags = array($userflag);
1472         $updateduserflags = mod_assign_external::set_user_flags($assign->id, $userflags);
1473         // We need to execute the return values cleaning process to simulate the web service server.
1474         $updateduserflags = external_api::clean_returnvalue(mod_assign_external::set_user_flags_returns(), $updateduserflags);
1476         $this->assertEquals($student->id, $updateduserflags[0]['userid']);
1477         $updateduserflag = $DB->get_record('assign_user_flags', array('id' => $updateduserflags[0]['id']));
1479         // Confirm that all data was updated correctly.
1480         $this->assertEquals($student->id,  $updateduserflag->userid);
1481         $this->assertEquals($assign->id, $updateduserflag->assignment);
1482         $this->assertEquals(0, $updateduserflag->locked);
1483         $this->assertEquals(2, $updateduserflag->mailed);
1484         $this->assertEquals(0, $updateduserflag->extensionduedate);
1485         $this->assertEquals('readyforreview', $updateduserflag->workflowstate);
1486         $this->assertEquals($USER->id, $updateduserflag->allocatedmarker);
1487     }
1489     /**
1490      * Test view_grading_table
1491      */
1492     public function test_view_grading_table() {
1493         global $DB;
1495         $this->resetAfterTest(true);
1497         $this->setAdminUser();
1498         // Setup test data.
1499         $course = $this->getDataGenerator()->create_course();
1500         $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1501         $context = context_module::instance($assign->cmid);
1502         $cm = get_coursemodule_from_instance('assign', $assign->id);
1504         // Test invalid instance id.
1505         try {
1506             mod_assign_external::view_grading_table(0);
1507             $this->fail('Exception expected due to invalid mod_assign instance id.');
1508         } catch (moodle_exception $e) {
1509             $this->assertEquals('invalidrecord', $e->errorcode);
1510         }
1512         // Test not-enrolled user.
1513         $user = self::getDataGenerator()->create_user();
1514         $this->setUser($user);
1515         try {
1516             mod_assign_external::view_grading_table($assign->id);
1517             $this->fail('Exception expected due to not enrolled user.');
1518         } catch (moodle_exception $e) {
1519             $this->assertEquals('requireloginerror', $e->errorcode);
1520         }
1522         // Test user with full capabilities.
1523         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1524         $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
1526         // Trigger and capture the event.
1527         $sink = $this->redirectEvents();
1529         $result = mod_assign_external::view_grading_table($assign->id);
1530         $result = external_api::clean_returnvalue(mod_assign_external::view_grading_table_returns(), $result);
1532         $events = $sink->get_events();
1533         $this->assertCount(1, $events);
1534         $event = array_shift($events);
1536         // Checking that the event contains the expected values.
1537         $this->assertInstanceOf('\mod_assign\event\grading_table_viewed', $event);
1538         $this->assertEquals($context, $event->get_context());
1539         $moodleurl = new \moodle_url('/mod/assign/view.php', array('id' => $cm->id));
1540         $this->assertEquals($moodleurl, $event->get_url());
1541         $this->assertEventContextNotUsed($event);
1542         $this->assertNotEmpty($event->get_name());
1544         // Test user with no capabilities.
1545         // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
1546         assign_capability('mod/assign:view', CAP_PROHIBIT, $teacherrole->id, $context->id);
1547         accesslib_clear_all_caches_for_unit_testing();
1549         try {
1550             mod_assign_external::view_grading_table($assign->id);
1551             $this->fail('Exception expected due to missing capability.');
1552         } catch (moodle_exception $e) {
1553             $this->assertEquals('nopermissions', $e->errorcode);
1554         }
1556     }