MDL-59239 mod_workshop: New WS mod_workshop_view_submission
[moodle.git] / mod / workshop / tests / external_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 /**
18  * Workshop module external functions tests
19  *
20  * @package    mod_workshop
21  * @category   external
22  * @copyright  2017 Juan Leyva <juan@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  * @since      Moodle 3.4
25  */
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
31 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32 require_once($CFG->dirroot . '/mod/workshop/lib.php');
34 use mod_workshop\external\workshop_summary_exporter;
35 use mod_workshop\external\submission_exporter;
37 /**
38  * Workshop module external functions tests
39  *
40  * @package    mod_workshop
41  * @category   external
42  * @copyright  2017 Juan Leyva <juan@moodle.com>
43  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44  * @since      Moodle 3.4
45  */
46 class mod_workshop_external_testcase extends externallib_advanced_testcase {
48     /** @var stdClass course object */
49     private $course;
50     /** @var stdClass workshop object */
51     private $workshop;
52     /** @var stdClass context object */
53     private $context;
54     /** @var stdClass cm object */
55     private $cm;
56     /** @var stdClass student object */
57     private $student;
58     /** @var stdClass teacher object */
59     private $teacher;
60     /** @var stdClass student role object */
61     private $studentrole;
62     /** @var stdClass teacher role object */
63     private $teacherrole;
65     /**
66      * Set up for every test
67      */
68     public function setUp() {
69         global $DB;
70         $this->resetAfterTest();
71         $this->setAdminUser();
73         // Setup test data.
74         $course = new stdClass();
75         $course->groupmode = SEPARATEGROUPS;
76         $course->groupmodeforce = true;
77         $this->course = $this->getDataGenerator()->create_course($course);
78         $this->workshop = $this->getDataGenerator()->create_module('workshop',
79             array(
80                 'course' => $this->course->id,
81                 'overallfeedbackfiles' => 1,
82             )
83         );
84         $this->context = context_module::instance($this->workshop->cmid);
85         $this->cm = get_coursemodule_from_instance('workshop', $this->workshop->id);
87         // Add grading strategy data (accumulative is the default).
88         $workshop = new workshop($this->workshop, $this->cm, $this->course);
89         $strategy = $workshop->grading_strategy_instance();
90         $data = array();
91         for ($i = 0; $i < 4; $i++) {
92             $data['dimensionid__idx_'.$i] = 0;
93             $data['description__idx_'.$i.'_editor'] = array('text' => "Content $i", 'format' => FORMAT_MOODLE);
94             $data['grade__idx_'.$i] = 25;
95             $data['weight__idx_'.$i] = 25;
96         }
97         $data['workshopid'] = $workshop->id;
98         $data['norepeats'] = 4;
99         $strategy->save_edit_strategy_form((object) $data);
101         // Create users.
102         $this->student = self::getDataGenerator()->create_user();
103         $this->anotherstudentg1 = self::getDataGenerator()->create_user();
104         $this->anotherstudentg2 = self::getDataGenerator()->create_user();
105         $this->teacher = self::getDataGenerator()->create_user();
107         // Users enrolments.
108         $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
109         $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
110         $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual');
111         $this->getDataGenerator()->enrol_user($this->anotherstudentg1->id, $this->course->id, $this->studentrole->id, 'manual');
112         $this->getDataGenerator()->enrol_user($this->anotherstudentg2->id, $this->course->id, $this->studentrole->id, 'manual');
113         $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
115         $this->group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
116         $this->group2 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
117         groups_add_member($this->group1, $this->student);
118         groups_add_member($this->group1, $this->anotherstudentg1);
119         groups_add_member($this->group2, $this->anotherstudentg2);
120     }
122     /**
123      * Test test_mod_workshop_get_workshops_by_courses
124      */
125     public function test_mod_workshop_get_workshops_by_courses() {
126         global $DB;
128         // Create additional course.
129         $course2 = self::getDataGenerator()->create_course();
131         // Second workshop.
132         $record = new stdClass();
133         $record->course = $course2->id;
134         $workshop2 = self::getDataGenerator()->create_module('workshop', $record);
136         // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
137         $enrol = enrol_get_plugin('manual');
138         $enrolinstances = enrol_get_instances($course2->id, true);
139         foreach ($enrolinstances as $courseenrolinstance) {
140             if ($courseenrolinstance->enrol == "manual") {
141                 $instance2 = $courseenrolinstance;
142                 break;
143             }
144         }
145         $enrol->enrol_user($instance2, $this->student->id, $this->studentrole->id);
147         self::setUser($this->student);
149         $returndescription = mod_workshop_external::get_workshops_by_courses_returns();
151         // Create what we expect to be returned when querying the two courses.
152         $properties = workshop_summary_exporter::read_properties_definition();
153         $expectedfields = array_keys($properties);
155         // Add expected coursemodule and data.
156         $workshop1 = $this->workshop;
157         $workshop1->coursemodule = $workshop1->cmid;
158         $workshop1->introformat = 1;
159         $workshop1->introfiles = [];
160         $workshop1->instructauthorsfiles = [];
161         $workshop1->instructauthorsformat = 1;
162         $workshop1->instructreviewersfiles = [];
163         $workshop1->instructreviewersformat = 1;
164         $workshop1->conclusionfiles = [];
165         $workshop1->conclusionformat = 1;
167         $workshop2->coursemodule = $workshop2->cmid;
168         $workshop2->introformat = 1;
169         $workshop2->introfiles = [];
170         $workshop2->instructauthorsfiles = [];
171         $workshop2->instructauthorsformat = 1;
172         $workshop2->instructreviewersfiles = [];
173         $workshop2->instructreviewersformat = 1;
174         $workshop2->conclusionfiles = [];
175         $workshop2->conclusionformat = 1;
177         foreach ($expectedfields as $field) {
178             if (!empty($properties[$field]) && $properties[$field]['type'] == PARAM_BOOL) {
179                 $workshop1->{$field} = (bool) $workshop1->{$field};
180                 $workshop2->{$field} = (bool) $workshop2->{$field};
181             }
182             $expected1[$field] = $workshop1->{$field};
183             $expected2[$field] = $workshop2->{$field};
184         }
186         $expectedworkshops = array($expected2, $expected1);
188         // Call the external function passing course ids.
189         $result = mod_workshop_external::get_workshops_by_courses(array($course2->id, $this->course->id));
190         $result = external_api::clean_returnvalue($returndescription, $result);
192         $this->assertEquals($expectedworkshops, $result['workshops']);
193         $this->assertCount(0, $result['warnings']);
195         // Call the external function without passing course id.
196         $result = mod_workshop_external::get_workshops_by_courses();
197         $result = external_api::clean_returnvalue($returndescription, $result);
198         $this->assertEquals($expectedworkshops, $result['workshops']);
199         $this->assertCount(0, $result['warnings']);
201         // Unenrol user from second course and alter expected workshops.
202         $enrol->unenrol_user($instance2, $this->student->id);
203         array_shift($expectedworkshops);
205         // Call the external function without passing course id.
206         $result = mod_workshop_external::get_workshops_by_courses();
207         $result = external_api::clean_returnvalue($returndescription, $result);
208         $this->assertEquals($expectedworkshops, $result['workshops']);
210         // Call for the second course we unenrolled the user from, expected warning.
211         $result = mod_workshop_external::get_workshops_by_courses(array($course2->id));
212         $this->assertCount(1, $result['warnings']);
213         $this->assertEquals('1', $result['warnings'][0]['warningcode']);
214         $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
215     }
217     /**
218      * Test mod_workshop_get_workshop_access_information for students.
219      */
220     public function test_mod_workshop_get_workshop_access_information_student() {
222         self::setUser($this->student);
223         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
224         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
225         // Check default values for capabilities.
226         $enabledcaps = array('canpeerassess', 'cansubmit', 'canview', 'canviewauthornames', 'canviewauthorpublished',
227             'canviewpublishedsubmissions', 'canexportsubmissions');
229         foreach ($result as $capname => $capvalue) {
230             if (strpos($capname, 'can') !== 0) {
231                 continue;
232             }
233             if (in_array($capname, $enabledcaps)) {
234                 $this->assertTrue($capvalue);
235             } else {
236                 $this->assertFalse($capvalue);
237             }
238         }
239         // Now, unassign some capabilities.
240         unassign_capability('mod/workshop:peerassess', $this->studentrole->id);
241         unassign_capability('mod/workshop:submit', $this->studentrole->id);
242         unset($enabledcaps[0]);
243         unset($enabledcaps[1]);
244         accesslib_clear_all_caches_for_unit_testing();
246         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
247         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
248         foreach ($result as $capname => $capvalue) {
249             if (strpos($capname, 'can') !== 0) {
250                 continue;
251             }
252             if (in_array($capname, $enabledcaps)) {
253                 $this->assertTrue($capvalue);
254             } else {
255                 $this->assertFalse($capvalue);
256             }
257         }
259         // Now, specific functionalities.
260         $this->assertFalse($result['creatingsubmissionallowed']);
261         $this->assertFalse($result['modifyingsubmissionallowed']);
262         $this->assertFalse($result['assessingallowed']);
263         $this->assertFalse($result['assessingexamplesallowed']);
264         $this->assertTrue($result['examplesassessedbeforesubmission']);
265         $this->assertTrue($result['examplesassessedbeforeassessment']);
267         // Switch phase.
268         $workshop = new workshop($this->workshop, $this->cm, $this->course);
269         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
270         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
271         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
273         $this->assertTrue($result['creatingsubmissionallowed']);
274         $this->assertTrue($result['modifyingsubmissionallowed']);
275         $this->assertFalse($result['assessingallowed']);
276         $this->assertFalse($result['assessingexamplesallowed']);
277         $this->assertTrue($result['examplesassessedbeforesubmission']);
278         $this->assertTrue($result['examplesassessedbeforeassessment']);
280         // Switch to next (to assessment).
281         $workshop = new workshop($this->workshop, $this->cm, $this->course);
282         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
283         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
284         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
286         $this->assertFalse($result['creatingsubmissionallowed']);
287         $this->assertFalse($result['modifyingsubmissionallowed']);
288         $this->assertTrue($result['assessingallowed']);
289         $this->assertFalse($result['assessingexamplesallowed']);
290         $this->assertTrue($result['examplesassessedbeforesubmission']);
291         $this->assertTrue($result['examplesassessedbeforeassessment']);
292     }
294     /**
295      * Test mod_workshop_get_workshop_access_information for teachers.
296      */
297     public function test_mod_workshop_get_workshop_access_information_teacher() {
299         self::setUser($this->teacher);
300         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
301         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
302         // Check default values.
303         $disabledcaps = array('canpeerassess', 'cansubmit');
305         foreach ($result as $capname => $capvalue) {
306             if (strpos($capname, 'can') !== 0) {
307                 continue;
308             }
309             if (in_array($capname, $disabledcaps)) {
310                 $this->assertFalse($capvalue);
311             } else {
312                 $this->assertTrue($capvalue);
313             }
314         }
316         // Now, specific functionalities.
317         $this->assertFalse($result['creatingsubmissionallowed']);
318         $this->assertFalse($result['modifyingsubmissionallowed']);
319         $this->assertFalse($result['assessingallowed']);
320         $this->assertFalse($result['assessingexamplesallowed']);
321     }
323     /**
324      * Test mod_workshop_get_user_plan for students.
325      */
326     public function test_mod_workshop_get_user_plan_student() {
328         self::setUser($this->student);
329         $result = mod_workshop_external::get_user_plan($this->workshop->id);
330         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
332         $this->assertCount(0, $result['userplan']['examples']);  // No examples given.
333         $this->assertCount(5, $result['userplan']['phases']);  // Always 5 phases.
334         $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']);  // First phase always setup.
335         $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
337         // Switch phase.
338         $workshop = new workshop($this->workshop, $this->cm, $this->course);
339         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
341         $result = mod_workshop_external::get_user_plan($this->workshop->id);
342         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
344         $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
345         $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
346     }
348     /**
349      * Test mod_workshop_get_user_plan for teachers.
350      */
351     public function test_mod_workshop_get_user_plan_teacher() {
352         global $DB;
354         self::setUser($this->teacher);
355         $result = mod_workshop_external::get_user_plan($this->workshop->id);
356         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
358         $this->assertCount(0, $result['userplan']['examples']);  // No examples given.
359         $this->assertCount(5, $result['userplan']['phases']);  // Always 5 phases.
360         $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']);  // First phase always setup.
361         $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
362         $this->assertCount(4, $result['userplan']['phases'][0]['tasks']);  // For new empty workshops, always 4 tasks.
364         foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
365             if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'editform') {
366                 $this->assertEquals(1, $task['completed']);
367             } else {
368                 $this->assertEmpty($task['completed']);
369             }
370         }
372         // Do some of the tasks asked - switch phase.
373         $workshop = new workshop($this->workshop, $this->cm, $this->course);
374         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
376         $result = mod_workshop_external::get_user_plan($this->workshop->id);
377         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
378         foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
379             if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'editform' ||
380                     $task['code'] == 'switchtonextphase') {
381                 $this->assertEquals(1, $task['completed']);
382             } else {
383                 $this->assertEmpty($task['completed']);
384             }
385         }
387         $result = mod_workshop_external::get_user_plan($this->workshop->id);
388         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
390         $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
391         $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
392     }
394     /**
395      * Test test_view_workshop invalid id.
396      */
397     public function test_view_workshop_invalid_id() {
398         $this->expectException('moodle_exception');
399         mod_workshop_external::view_workshop(0);
400     }
402     /**
403      * Test test_view_workshop user not enrolled.
404      */
405     public function test_view_workshop_user_not_enrolled() {
406         // Test not-enrolled user.
407         $usernotenrolled = self::getDataGenerator()->create_user();
408         $this->setUser($usernotenrolled);
409         $this->expectException('moodle_exception');
410         mod_workshop_external::view_workshop($this->workshop->id);
411     }
413     /**
414      * Test test_view_workshop user student.
415      */
416     public function test_view_workshop_user_student() {
417         // Test user with full capabilities.
418         $this->setUser($this->student);
420         // Trigger and capture the event.
421         $sink = $this->redirectEvents();
423         $result = mod_workshop_external::view_workshop($this->workshop->id);
424         $result = external_api::clean_returnvalue(mod_workshop_external::view_workshop_returns(), $result);
425         $this->assertTrue($result['status']);
427         $events = $sink->get_events();
428         $this->assertCount(1, $events);
429         $event = array_shift($events);
431         // Checking that the event contains the expected values.
432         $this->assertInstanceOf('\mod_workshop\event\course_module_viewed', $event);
433         $this->assertEquals($this->context, $event->get_context());
434         $moodleworkshop = new \moodle_url('/mod/workshop/view.php', array('id' => $this->cm->id));
435         $this->assertEquals($moodleworkshop, $event->get_url());
436         $this->assertEventContextNotUsed($event);
437         $this->assertNotEmpty($event->get_name());
438     }
440     /**
441      * Test test_view_workshop user missing capabilities.
442      */
443     public function test_view_workshop_user_missing_capabilities() {
444         // Test user with no capabilities.
445         // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
446         assign_capability('mod/workshop:view', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
447         // Empty all the caches that may be affected  by this change.
448         accesslib_clear_all_caches_for_unit_testing();
449         course_modinfo::clear_instance_cache();
451         $this->setUser($this->student);
452         $this->expectException('moodle_exception');
453         mod_workshop_external::view_workshop($this->workshop->id);
454     }
456     /**
457      * Test test_add_submission.
458      */
459     public function test_add_submission() {
460         $fs = get_file_storage();
462         // Test user with full capabilities.
463         $this->setUser($this->student);
465         $title = 'Submission title';
466         $content = 'Submission contents';
468         // Create a file in a draft area for inline attachments.
469         $draftidinlineattach = file_get_unused_draft_itemid();
470         $usercontext = context_user::instance($this->student->id);
471         $filenameimg = 'shouldbeanimage.txt';
472         $filerecordinline = array(
473             'contextid' => $usercontext->id,
474             'component' => 'user',
475             'filearea'  => 'draft',
476             'itemid'    => $draftidinlineattach,
477             'filepath'  => '/',
478             'filename'  => $filenameimg,
479         );
480         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
482         // Create a file in a draft area for regular attachments.
483         $draftidattach = file_get_unused_draft_itemid();
484         $filerecordattach = $filerecordinline;
485         $attachfilename = 'attachment.txt';
486         $filerecordattach['filename'] = $attachfilename;
487         $filerecordattach['itemid'] = $draftidattach;
488         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
490         // Switch to submission phase.
491         $workshop = new workshop($this->workshop, $this->cm, $this->course);
492         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
494         $result = mod_workshop_external::add_submission($this->workshop->id, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
495             $draftidattach);
496         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
497         $this->assertEmpty($result['warnings']);
499         // Check submission created.
500         $submission = $workshop->get_submission_by_author($this->student->id);
501         $this->assertTrue($result['status']);
502         $this->assertEquals($result['submissionid'], $submission->id);
503         $this->assertEquals($title, $submission->title);
504         $this->assertEquals($content, $submission->content);
506         // Check files.
507         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_content', $submission->id);
508         $this->assertCount(2, $contentfiles);
509         foreach ($contentfiles as $file) {
510             if ($file->is_directory()) {
511                 continue;
512             } else {
513                 $this->assertEquals($filenameimg, $file->get_filename());
514             }
515         }
516         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_attachment', $submission->id);
517         $this->assertCount(2, $contentfiles);
518         foreach ($contentfiles as $file) {
519             if ($file->is_directory()) {
520                 continue;
521             } else {
522                 $this->assertEquals($attachfilename, $file->get_filename());
523             }
524         }
525     }
527     /**
528      * Test test_add_submission invalid phase.
529      */
530     public function test_add_submission_invalid_phase() {
531         $this->setUser($this->student);
533         $this->expectException('moodle_exception');
534         mod_workshop_external::add_submission($this->workshop->id, 'Test');
535     }
537     /**
538      * Test test_add_submission empty title.
539      */
540     public function test_add_submission_empty_title() {
541         $this->setUser($this->student);
543         // Switch to submission phase.
544         $workshop = new workshop($this->workshop, $this->cm, $this->course);
545         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
547         $this->expectException('moodle_exception');
548         mod_workshop_external::add_submission($this->workshop->id, '');
549     }
551     /**
552      * Test test_add_submission already added.
553      */
554     public function test_add_submission_already_added() {
555         $this->setUser($this->student);
557         // Switch to submission phase.
558         $workshop = new workshop($this->workshop, $this->cm, $this->course);
559         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
561         // Create the submission.
562         $result = mod_workshop_external::add_submission($this->workshop->id, 'My submission');
563         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
565         // Try to create it again.
566         $result = mod_workshop_external::add_submission($this->workshop->id, 'My submission');
567         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
568         $this->assertFalse($result['status']);
569         $this->assertArrayNotHasKey('submissionid', $result);
570         $this->assertCount(2, $result['warnings']);
571         $this->assertEquals('fielderror', $result['warnings'][0]['warningcode']);
572         $this->assertEquals('content_editor', $result['warnings'][0]['item']);
573         $this->assertEquals('fielderror', $result['warnings'][1]['warningcode']);
574         $this->assertEquals('attachment_filemanager', $result['warnings'][1]['item']);
575     }
577     /**
578      * Helper method to create a submission for testing for the given user.
579      *
580      * @param int $user the submission will be created by this student.
581      * @return int the submission id
582      */
583     protected function create_test_submission($user) {
584         // Test user with full capabilities.
585         $this->setUser($user);
587         $title = 'Submission title';
588         $content = 'Submission contents';
590         // Create a file in a draft area for inline attachments.
591         $fs = get_file_storage();
592         $draftidinlineattach = file_get_unused_draft_itemid();
593         $usercontext = context_user::instance($this->student->id);
594         $filenameimg = 'shouldbeanimage.txt';
595         $filerecordinline = array(
596             'contextid' => $usercontext->id,
597             'component' => 'user',
598             'filearea'  => 'draft',
599             'itemid'    => $draftidinlineattach,
600             'filepath'  => '/',
601             'filename'  => $filenameimg,
602         );
603         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
605         // Create a file in a draft area for regular attachments.
606         $draftidattach = file_get_unused_draft_itemid();
607         $filerecordattach = $filerecordinline;
608         $attachfilename = 'attachment.txt';
609         $filerecordattach['filename'] = $attachfilename;
610         $filerecordattach['itemid'] = $draftidattach;
611         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
613         // Switch to submission phase.
614         $workshop = new workshop($this->workshop, $this->cm, $this->course);
615         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
617         $result = mod_workshop_external::add_submission($this->workshop->id, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
618             $draftidattach);
619         return $result['submissionid'];
620     }
622     /**
623      * Test test_update_submission.
624      */
625     public function test_update_submission() {
627         // Create the submission that will be updated.
628         $submissionid = $this->create_test_submission($this->student);
630         // Test user with full capabilities.
631         $this->setUser($this->student);
633         $title = 'Submission new title';
634         $content = 'Submission new contents';
636         // Create a different file in a draft area for inline attachments.
637         $fs = get_file_storage();
638         $draftidinlineattach = file_get_unused_draft_itemid();
639         $usercontext = context_user::instance($this->student->id);
640         $filenameimg = 'shouldbeanimage_new.txt';
641         $filerecordinline = array(
642             'contextid' => $usercontext->id,
643             'component' => 'user',
644             'filearea'  => 'draft',
645             'itemid'    => $draftidinlineattach,
646             'filepath'  => '/',
647             'filename'  => $filenameimg,
648         );
649         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
651         // Create a different file in a draft area for regular attachments.
652         $draftidattach = file_get_unused_draft_itemid();
653         $filerecordattach = $filerecordinline;
654         $attachfilename = 'attachment_new.txt';
655         $filerecordattach['filename'] = $attachfilename;
656         $filerecordattach['itemid'] = $draftidattach;
657         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
659         $result = mod_workshop_external::update_submission($submissionid, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
660             $draftidattach);
661         $result = external_api::clean_returnvalue(mod_workshop_external::update_submission_returns(), $result);
662         $this->assertEmpty($result['warnings']);
664         // Check submission updated.
665         $workshop = new workshop($this->workshop, $this->cm, $this->course);
666         $submission = $workshop->get_submission_by_id($submissionid);
667         $this->assertTrue($result['status']);
668         $this->assertEquals($title, $submission->title);
669         $this->assertEquals($content, $submission->content);
671         // Check files.
672         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_content', $submission->id);
673         $this->assertCount(2, $contentfiles);
674         foreach ($contentfiles as $file) {
675             if ($file->is_directory()) {
676                 continue;
677             } else {
678                 $this->assertEquals($filenameimg, $file->get_filename());
679             }
680         }
681         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_attachment', $submission->id);
682         $this->assertCount(2, $contentfiles);
683         foreach ($contentfiles as $file) {
684             if ($file->is_directory()) {
685                 continue;
686             } else {
687                 $this->assertEquals($attachfilename, $file->get_filename());
688             }
689         }
690     }
692     /**
693      * Test test_update_submission belonging to other user.
694      */
695     public function test_update_submission_of_other_user() {
696         // Create the submission that will be updated.
697         $submissionid = $this->create_test_submission($this->student);
699         $this->setUser($this->teacher);
701         $this->expectException('moodle_exception');
702         mod_workshop_external::update_submission($submissionid, 'Test');
703     }
705     /**
706      * Test test_update_submission invalid phase.
707      */
708     public function test_update_submission_invalid_phase() {
709         // Create the submission that will be updated.
710         $submissionid = $this->create_test_submission($this->student);
712         $this->setUser($this->student);
714         // Switch to assessment phase.
715         $workshop = new workshop($this->workshop, $this->cm, $this->course);
716         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
718         $this->expectException('moodle_exception');
719         mod_workshop_external::update_submission($submissionid, 'Test');
720     }
722     /**
723      * Test test_update_submission empty title.
724      */
725     public function test_update_submission_empty_title() {
726         // Create the submission that will be updated.
727         $submissionid = $this->create_test_submission($this->student);
729         $this->setUser($this->student);
731         $this->expectException('moodle_exception');
732         mod_workshop_external::update_submission($submissionid, '');
733     }
735     /**
736      * Test test_delete_submission.
737      */
738     public function test_delete_submission() {
740         // Create the submission that will be deleted.
741         $submissionid = $this->create_test_submission($this->student);
743         $this->setUser($this->student);
745         // Trigger and capture the event.
746         $sink = $this->redirectEvents();
748         $result = mod_workshop_external::delete_submission($submissionid);
749         $result = external_api::clean_returnvalue(mod_workshop_external::delete_submission_returns(), $result);
750         $this->assertEmpty($result['warnings']);
751         $this->assertTrue($result['status']);
752         $workshop = new workshop($this->workshop, $this->cm, $this->course);
753         $submission = $workshop->get_submission_by_author($this->student->id);
754         $this->assertFalse($submission);
756         $events = $sink->get_events();
757         $this->assertCount(1, $events);
758         $event = array_shift($events);
760         // Checking event.
761         $this->assertInstanceOf('\mod_workshop\event\submission_deleted', $event);
762         $this->assertEquals($this->context, $event->get_context());
763     }
765     /**
766      * Test test_delete_submission_with_assessments.
767      */
768     public function test_delete_submission_with_assessments() {
770         // Create the submission that will be deleted.
771         $submissionid = $this->create_test_submission($this->student);
773         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
774         $workshopgenerator->create_assessment($submissionid, $this->teacher->id, array(
775             'weight' => 3,
776             'grade' => 95.00000,
777         ));
779         $this->setUser($this->student);
780         $this->expectException('moodle_exception');
781         mod_workshop_external::delete_submission($submissionid);
782     }
784     /**
785      * Test test_delete_submission_invalid_phase.
786      */
787     public function test_delete_submission_invalid_phase() {
789         // Create the submission that will be deleted.
790         $submissionid = $this->create_test_submission($this->student);
792         // Switch to assessment phase.
793         $workshop = new workshop($this->workshop, $this->cm, $this->course);
794         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
796         $this->setUser($this->student);
797         $this->expectException('moodle_exception');
798         mod_workshop_external::delete_submission($submissionid);
799     }
801     /**
802      * Test test_delete_submission_as_teacher.
803      */
804     public function test_delete_submission_as_teacher() {
806         // Create the submission that will be deleted.
807         $submissionid = $this->create_test_submission($this->student);
809         $this->setUser($this->teacher);
810         $result = mod_workshop_external::delete_submission($submissionid);
811         $result = external_api::clean_returnvalue(mod_workshop_external::delete_submission_returns(), $result);
812         $this->assertEmpty($result['warnings']);
813         $this->assertTrue($result['status']);
814     }
816     /**
817      * Test test_delete_submission_other_user.
818      */
819     public function test_delete_submission_other_user() {
821         $anotheruser = self::getDataGenerator()->create_user();
822         $this->getDataGenerator()->enrol_user($anotheruser->id, $this->course->id, $this->studentrole->id, 'manual');
823         // Create the submission that will be deleted.
824         $submissionid = $this->create_test_submission($this->student);
826         $this->setUser($anotheruser);
827         $this->expectException('moodle_exception');
828         mod_workshop_external::delete_submission($submissionid);
829     }
831     /**
832      * Test test_get_submissions_student.
833      */
834     public function test_get_submissions_student() {
836         // Create a couple of submissions with files.
837         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
838         $secondsubmissionid = $this->create_test_submission($this->anotherstudentg1->id);
840         $this->setUser($this->student);
841         $result = mod_workshop_external::get_submissions($this->workshop->id);
842         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
843         // We should get just our submission.
844         $this->assertCount(1, $result['submissions']);
845         $this->assertEquals(1, $result['totalcount']);
846         $this->assertEquals($firstsubmissionid, $result['submissions'][0]['id']);
847         $this->assertCount(1, $result['submissions'][0]['contentfiles']); // Check we retrieve submission text files.
848         $this->assertCount(1, $result['submissions'][0]['attachmentfiles']); // Check we retrieve attachment files.
849         // We shoul not see the grade or feedback information.
850         $properties = submission_exporter::properties_definition();
851         foreach ($properties as $attribute => $settings) {
852             if (!empty($settings['optional'])) {
853                 if (isset($result['submissions'][0][$attribute])) {
854                     echo "error $attribute";
855                 }
856                 $this->assertFalse(isset($result['submissions'][0][$attribute]));
857             }
858         }
859     }
861     /**
862      * Test test_get_submissions_published_student.
863      */
864     public function test_get_submissions_published_student() {
865         global $DB;
867         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
868         // Create a couple of submissions with files.
869         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
870         $submission = array('published' => 1);
871         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id, $submission);
873         $this->setUser($this->student);
874         $result = mod_workshop_external::get_submissions($this->workshop->id);
875         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
876         // We should get just our submission.
877         $this->assertCount(1, $result['submissions']);
878         $this->assertEquals(1, $result['totalcount']);
879         $this->assertEquals($submissionid, $result['submissions'][0]['id']);
881         // Check with group restrictions.
882         $this->setUser($this->anotherstudentg2);
883         $result = mod_workshop_external::get_submissions($this->workshop->id);
884         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
885         $this->assertCount(0, $result['submissions']);  // I can't see other users in separated groups.
886         $this->assertEquals(0, $result['totalcount']);
887     }
889     /**
890      * Test test_get_submissions_from_student_with_feedback_from_teacher.
891      */
892     public function test_get_submissions_from_student_with_feedback_from_teacher() {
893         global $DB;
895         // Create a couple of submissions with files.
896         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
897         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
898         // Create teacher feedback for submission.
899         $record = new stdclass();
900         $record->id = $submissionid;
901         $record->gradeover = 9;
902         $record->gradeoverby = $this->teacher->id;
903         $record->feedbackauthor = 'Hey';
904         $record->feedbackauthorformat = FORMAT_MOODLE;
905         $record->published = 1;
906         $DB->update_record('workshop_submissions', $record);
908         // Remove teacher caps.
909         assign_capability('mod/workshop:viewallsubmissions', CAP_PROHIBIT, $this->teacher->id, $this->context->id);
910         // Empty all the caches that may be affected  by this change.
911         accesslib_clear_all_caches_for_unit_testing();
912         course_modinfo::clear_instance_cache();
914         $this->setUser($this->teacher);
915         $result = mod_workshop_external::get_submissions($this->workshop->id, $this->student->id);
916         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
917         // We should get just our submission.
918         $this->assertEquals(1, $result['totalcount']);
919         $this->assertEquals($submissionid, $result['submissions'][0]['id']);
920     }
922     /**
923      * Test test_get_submissions_from_students_as_teacher.
924      */
925     public function test_get_submissions_from_students_as_teacher() {
926         global $DB;
928         // Create a couple of submissions with files.
929         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
930         $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
931         $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
932         $submissionid3 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg2->id);
934         $this->setUser($this->teacher);
935         $result = mod_workshop_external::get_submissions($this->workshop->id); // Get all.
936         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
937         $this->assertEquals(3, $result['totalcount']);
938         $this->assertCount(3, $result['submissions']);
940         $result = mod_workshop_external::get_submissions($this->workshop->id, 0, 0, 0, 2); // Check pagination.
941         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
942         $this->assertEquals(3, $result['totalcount']);
943         $this->assertCount(2, $result['submissions']);
945         $result = mod_workshop_external::get_submissions($this->workshop->id, 0, $this->group2->id); // Get group 2.
946         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
947         $this->assertEquals(1, $result['totalcount']);
948         $this->assertCount(1, $result['submissions']);
949         $this->assertEquals($submissionid3, $result['submissions'][0]['id']);
951         $result = mod_workshop_external::get_submissions($this->workshop->id, $this->anotherstudentg1->id); // Get one.
952         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
953         $this->assertEquals(1, $result['totalcount']);
954         $this->assertEquals($submissionid2, $result['submissions'][0]['id']);
955     }
957     /**
958      * Test test_get_submission_student.
959      */
960     public function test_get_submission_student() {
962         // Create a couple of submissions with files.
963         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
965         $this->setUser($this->student);
966         $result = mod_workshop_external::get_submission($firstsubmissionid);
967         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
968         $this->assertEquals($firstsubmissionid, $result['submission']['id']);
969         $this->assertCount(1, $result['submission']['contentfiles']); // Check we retrieve submission text files.
970         $this->assertCount(1, $result['submission']['attachmentfiles']); // Check we retrieve attachment files.
971     }
973     /**
974      * Test test_get_submission_i_reviewed.
975      */
976     public function test_get_submission_i_reviewed() {
978         // Create a couple of submissions with files.
979         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
980         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
981         $workshopgenerator->create_assessment($firstsubmissionid, $this->anotherstudentg1->id, array(
982             'weight' => 3,
983             'grade' => 95,
984         ));
985         // Now try to get the submission I just reviewed.
986         $this->setUser($this->anotherstudentg1);
987         $result = mod_workshop_external::get_submission($firstsubmissionid);
988         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
989         $this->assertEquals($firstsubmissionid, $result['submission']['id']);
990         $this->assertCount(1, $result['submission']['contentfiles']); // Check we retrieve submission text files.
991         $this->assertCount(1, $result['submission']['attachmentfiles']); // Check we retrieve attachment files.
992     }
994     /**
995      * Test test_get_submission_other_student.
996      */
997     public function test_get_submission_other_student() {
999         // Create a couple of submissions with files.
1000         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
1001         // Expect failure.
1002         $this->setUser($this->anotherstudentg1);
1003         $this->expectException('moodle_exception');
1004         $result = mod_workshop_external::get_submission($firstsubmissionid);
1005     }
1007     /**
1008      * Test test_get_submission_published_student.
1009      */
1010     public function test_get_submission_published_student() {
1011         global $DB;
1013         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
1014         // Create a couple of submissions with files.
1015         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1016         $submission = array('published' => 1);
1017         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id, $submission);
1019         $this->setUser($this->student);
1020         $result = mod_workshop_external::get_submission($submissionid);
1021         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1022         $this->assertEquals($submissionid, $result['submission']['id']);
1023         // Check that the student don't see the other student grade/feedback data even if is published.
1024         // We shoul not see the grade or feedback information.
1025         $properties = submission_exporter::properties_definition();
1026         foreach ($properties as $attribute => $settings) {
1027             if (!empty($settings['optional'])) {
1028                 if (isset($result['submission'][$attribute])) {
1029                     echo "error $attribute";
1030                 }
1031                 $this->assertFalse(isset($result['submission'][$attribute]));
1032             }
1033         }
1035         // Check with group restrictions.
1036         $this->setUser($this->anotherstudentg2);
1037         $this->expectException('moodle_exception');
1038         mod_workshop_external::get_submission($submissionid);
1039     }
1041     /**
1042      * Test test_get_submission_from_student_with_feedback_from_teacher.
1043      */
1044     public function test_get_submission_from_student_with_feedback_from_teacher() {
1045         global $DB;
1047         // Create a couple of submissions with files.
1048         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1049         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1050         // Create teacher feedback for submission.
1051         $record = new stdclass();
1052         $record->id = $submissionid;
1053         $record->gradeover = 9;
1054         $record->gradeoverby = $this->teacher->id;
1055         $record->feedbackauthor = 'Hey';
1056         $record->feedbackauthorformat = FORMAT_MOODLE;
1057         $record->published = 1;
1058         $DB->update_record('workshop_submissions', $record);
1060         // Remove teacher caps.
1061         assign_capability('mod/workshop:viewallsubmissions', CAP_PROHIBIT, $this->teacher->id, $this->context->id);
1062         // Empty all the caches that may be affected  by this change.
1063         accesslib_clear_all_caches_for_unit_testing();
1064         course_modinfo::clear_instance_cache();
1066         $this->setUser($this->teacher);
1067         $result = mod_workshop_external::get_submission($submissionid);
1068         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1069         $this->assertEquals($submissionid, $result['submission']['id']);
1070     }
1072     /**
1073      * Test test_get_submission_from_students_as_teacher.
1074      */
1075     public function test_get_submission_from_students_as_teacher() {
1076         // Create a couple of submissions with files.
1077         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1078         $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1079         $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
1080         $submissionid3 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg2->id);
1082         $this->setUser($this->teacher);
1083         $result = mod_workshop_external::get_submission($submissionid1); // Get all.
1084         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1085         $this->assertEquals($submissionid1, $result['submission']['id']);
1087         $result = mod_workshop_external::get_submission($submissionid3); // Get group 2.
1088         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1089         $this->assertEquals($submissionid3, $result['submission']['id']);
1090     }
1093     /**
1094      * Test get_submission_assessments_student.
1095      */
1096     public function test_get_submission_assessments_student() {
1097         global $DB;
1099         // Create the submission that will be deleted.
1100         $submissionid = $this->create_test_submission($this->student);
1102         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1103         $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1104             'weight' => 3,
1105             'grade' => 95,
1106         ));
1107         $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1108             'weight' => 2,
1109             'grade' => 90,
1110         ));
1112         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
1113         $this->setUser($this->student);
1114         $result = mod_workshop_external::get_submission_assessments($submissionid);
1115         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_assessments_returns(), $result);
1116         $this->assertCount(2, $result['assessments']);  // I received my two assessments.
1117         foreach ($result['assessments'] as $assessment) {
1118             if ($assessment['grade'] == 90) {
1119                 // My own assessment, I can see me.
1120                 $this->assertEquals($this->student->id, $assessment['reviewerid']);
1121             } else {
1122                 // Student's can't see who did the review.
1123                 $this->assertEquals(0, $assessment['reviewerid']);
1124             }
1125         }
1126     }
1128     /**
1129      * Test get_submission_assessments_invalid_phase.
1130      */
1131     public function test_get_submission_assessments_invalid_phase() {
1132         global $DB;
1134         // Create the submission that will be deleted.
1135         $submissionid = $this->create_test_submission($this->student);
1137         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1138         $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1139             'weight' => 3,
1140             'grade' => 95,
1141         ));
1143         $this->expectException('moodle_exception');
1144         mod_workshop_external::get_submission_assessments($submissionid);
1145     }
1147     /**
1148      * Test get_submission_assessments_teacher.
1149      */
1150     public function test_get_submission_assessments_teacher() {
1152         // Create the submission that will be deleted.
1153         $submissionid = $this->create_test_submission($this->student);
1155         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1156         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1157             'weight' => 1,
1158             'grade' => 50,
1159         ));
1161         $this->setUser($this->teacher);
1162         $result = mod_workshop_external::get_submission_assessments($submissionid);
1163         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_assessments_returns(), $result);
1164         $this->assertCount(1, $result['assessments']);
1165         $this->assertEquals(50, $result['assessments'][0]['grade']);
1166         $this->assertEquals($assessmentid, $result['assessments'][0]['id']);
1167     }
1169     /**
1170      * Test get_assessment_author.
1171      */
1172     public function test_get_assessment_author() {
1173         global $DB;
1175         // Create the submission.
1176         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1178         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1179         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1180             'weight' => 2,
1181             'grade' => 90,
1182         ));
1184         // Switch to closed phase.
1185         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
1186         $this->setUser($this->anotherstudentg1);
1187         $result = mod_workshop_external::get_assessment($assessmentid);
1188         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1189         $this->assertEquals($assessmentid, $result['assessment']['id']);
1190         $this->assertEquals(90, $result['assessment']['grade']);
1191         // I can't see the reviewer review.
1192         $this->assertFalse(isset($result['assessment']['feedbackreviewer']));
1193     }
1195     /**
1196      * Test get_assessment_reviewer.
1197      */
1198     public function test_get_assessment_reviewer() {
1199         global $DB;
1201         // Create the submission.
1202         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1204         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1205         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1206             'weight' => 2,
1207             'grade' => 90,
1208         ));
1210         // Switch to closed phase.
1211         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
1212         $this->setUser($this->student);
1213         $result = mod_workshop_external::get_assessment($assessmentid);
1214         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1215         $this->assertEquals($assessmentid, $result['assessment']['id']);
1216         $this->assertEquals(90, $result['assessment']['grade']);
1217         // I can see the reviewer review.
1218         $this->assertTrue(isset($result['assessment']['feedbackreviewer']));
1219     }
1221     /**
1222      * Test get_assessment_teacher.
1223      */
1224     public function test_get_assessment_teacher() {
1225         global $DB;
1227         // Create the submission.
1228         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1230         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1231         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1232             'weight' => 2,
1233             'grade' => 90,
1234         ));
1236         // Switch to closed phase.
1237         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
1238         $this->setUser($this->teacher);
1239         $result = mod_workshop_external::get_assessment($assessmentid);
1240         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1241         $this->assertEquals($assessmentid, $result['assessment']['id']);
1242         $this->assertEquals(90, $result['assessment']['grade']);
1243     }
1245     /**
1246      * Test get_assessment_student_invalid_phase.
1247      */
1248     public function test_get_assessment_student_invalid_phase() {
1249         global $DB;
1251         // Create the submission.
1252         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1254         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1255         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1256             'weight' => 2,
1257             'grade' => 90,
1258         ));
1260         // Switch to closed phase.
1261         $this->setUser($this->anotherstudentg1);
1263         $this->setExpectedException('moodle_exception');
1264         mod_workshop_external::get_assessment($assessmentid);
1265     }
1267     /**
1268      * Test get_assessment_student_invalid_user.
1269      */
1270     public function test_get_assessment_student_invalid_user() {
1271         global $DB;
1273         // Create the submission.
1274         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1276         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1277         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1278             'weight' => 2,
1279             'grade' => 90,
1280         ));
1282         // Switch to closed phase.
1283         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
1284         $this->setUser($this->anotherstudentg2);
1286         $this->setExpectedException('moodle_exception');
1287         mod_workshop_external::get_assessment($assessmentid);
1288     }
1290     /**
1291      * Test get_assessment_form_definition_reviewer_new_assessment.
1292      */
1293     public function test_get_assessment_form_definition_reviewer_new_assessment() {
1294         global $DB;
1296         // Create the submission.
1297         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1299         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1300         $submission = $workshop->get_submission_by_id($submissionid);
1301         $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1303         // Switch to assessment phase.
1304         $DB->set_field('workshop', 'phase', workshop::PHASE_ASSESSMENT, array('id' => $this->workshop->id));
1305         $this->setUser($this->student);
1306         $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1307         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1308         $this->assertEquals(4, $result['dimenssionscount']);    // We receive the expected 4 dimensions.
1309         $this->assertEmpty($result['current']); // Assessment not yet done.
1310         foreach ($result['fields'] as $field) {
1311             if (strpos($field['name'], 'grade__idx_') === 0) {
1312                 $this->assertEquals(25, $field['value']); // Check one of the dimension fields attributes.
1313             }
1314         }
1315     }
1317     /**
1318      * Test get_assessment_form_definition_teacher_new_assessment.
1319      */
1320     public function test_get_assessment_form_definition_teacher_new_assessment() {
1321         global $DB;
1323         // Create the submission.
1324         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1326         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1327         $submission = $workshop->get_submission_by_id($submissionid);
1328         $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1330         // Switch to assessment phase.
1331         $DB->set_field('workshop', 'phase', workshop::PHASE_ASSESSMENT, array('id' => $this->workshop->id));
1332         $this->setUser($this->teacher);
1333         $this->setExpectedException('moodle_exception');
1334         mod_workshop_external::get_assessment_form_definition($assessmentid);   // Teachers can't add/edit assessments.
1335     }
1337     /**
1338      * Test get_assessment_form_definition_invalid_phase.
1339      */
1340     public function test_get_assessment_form_definition_invalid_phase() {
1341         global $DB;
1343         // Create the submission.
1344         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1346         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1347         $submission = $workshop->get_submission_by_id($submissionid);
1348         $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1350         $this->setUser($this->student);
1351         $this->setExpectedException('moodle_exception');
1352         mod_workshop_external::get_assessment_form_definition($assessmentid);
1353     }
1355     /**
1356      * Test get_reviewer_assessments.
1357      */
1358     public function test_get_reviewer_assessments() {
1359         global $DB;
1361         // Create the submission.
1362         $submissionid1 = $this->create_test_submission($this->student);
1363         $submissionid2 = $this->create_test_submission($this->anotherstudentg1);
1365         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1366         $assessmentid1 = $workshopgenerator->create_assessment($submissionid1, $this->student->id, array(
1367             'weight' => 2,
1368             'grade' => 90,
1369         ));
1370         $assessmentid2 = $workshopgenerator->create_assessment($submissionid2, $this->student->id, array(
1371             'weight' => 3,
1372             'grade' => 80,
1373         ));
1375         // Switch to assessment phase.
1376         $DB->set_field('workshop', 'phase', workshop::PHASE_ASSESSMENT, array('id' => $this->workshop->id));
1377         $this->setUser($this->student);
1378         // Get my assessments.
1379         $result = mod_workshop_external::get_reviewer_assessments($this->workshop->id);
1380         $result = external_api::clean_returnvalue(mod_workshop_external::get_reviewer_assessments_returns(), $result);
1381         $this->assertCount(2, $result['assessments']);
1382         foreach ($result['assessments'] as $assessment) {
1383             if ($assessment['id'] == $assessmentid1) {
1384                 $this->assertEquals(90, $assessment['grade']);
1385             } else {
1386                 $this->assertEquals($assessmentid2, $assessment['id']);
1387                 $this->assertEquals(80, $assessment['grade']);
1388             }
1389         }
1391         // Now, as teacher try to get the same student assessments.
1392         $result = mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->student->id);
1393         $result = external_api::clean_returnvalue(mod_workshop_external::get_reviewer_assessments_returns(), $result);
1394         $this->assertCount(2, $result['assessments']);
1395     }
1397     /**
1398      * Test get_reviewer_assessments_other_student.
1399      */
1400     public function test_get_reviewer_assessments_other_student() {
1401         global $DB;
1403         $DB->set_field('workshop', 'phase', workshop::PHASE_ASSESSMENT, array('id' => $this->workshop->id));
1404         // Try to get other user assessments.
1405         $this->setUser($this->student);
1406         $this->setExpectedException('moodle_exception');
1407         mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->anotherstudentg1->id);
1408     }
1410     /**
1411      * Test get_reviewer_assessments_invalid_phase.
1412      */
1413     public function test_get_reviewer_assessments_invalid_phase() {
1414         global $DB;
1416         $DB->set_field('workshop', 'phase', workshop::PHASE_SUBMISSION, array('id' => $this->workshop->id));
1417         // Try to get other user assessments.
1418         $this->setUser($this->student);
1419         $this->setExpectedException('moodle_exception');
1420         mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->anotherstudentg1->id);
1421     }
1423     /**
1424      * Test update_assessment.
1425      */
1426     public function test_update_assessment() {
1427         global $DB;
1429         // Create the submission.
1430         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1432         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1433         $submission = $workshop->get_submission_by_id($submissionid);
1434         $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1436         // Switch to assessment phase.
1437         $DB->set_field('workshop', 'phase', workshop::PHASE_ASSESSMENT, array('id' => $this->workshop->id));
1438         $this->setUser($this->student);
1439         // Get the form definition.
1440         $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1441         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1443         // Prepare the data to be sent.
1444         $data = $result['fields'];
1445         foreach ($data as $key => $param) {
1446             if (strpos($param['name'], 'peercomment__idx_') === 0) {
1447                 $data[$key]['value'] = 'Some content';
1448             } else if (strpos($param['name'], 'grade__idx_') === 0) {
1449                 $data[$key]['value'] = 25; // Set all to 25.
1450             }
1451         }
1453         // Required data.
1454         $data[] = array(
1455             'name' => 'nodims',
1456             'value' => $result['dimenssionscount'],
1457         );
1459         // General feedback.
1460         $data[] = array(
1461             'name' => 'feedbackauthor',
1462             'value' => 'Feedback for the author',
1463         );
1464         $data[] = array(
1465             'name' => 'feedbackauthorformat',
1466             'value' => FORMAT_MOODLE,
1467         );
1469         // Create a file in a draft area for inline attachments.
1470         $fs = get_file_storage();
1471         $draftidinlineattach = file_get_unused_draft_itemid();
1472         $usercontext = context_user::instance($this->student->id);
1473         $filenameimg = 'shouldbeanimage.txt';
1474         $filerecordinline = array(
1475             'contextid' => $usercontext->id,
1476             'component' => 'user',
1477             'filearea'  => 'draft',
1478             'itemid'    => $draftidinlineattach,
1479             'filepath'  => '/',
1480             'filename'  => $filenameimg,
1481         );
1482         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
1484         // Create a file in a draft area for regular attachments.
1485         $draftidattach = file_get_unused_draft_itemid();
1486         $filerecordattach = $filerecordinline;
1487         $attachfilename = 'attachment.txt';
1488         $filerecordattach['filename'] = $attachfilename;
1489         $filerecordattach['itemid'] = $draftidattach;
1490         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
1492         $data[] = array(
1493             'name' => 'feedbackauthorinlineattachmentsid',
1494             'value' => $draftidinlineattach,
1495         );
1496         $data[] = array(
1497             'name' => 'feedbackauthorattachmentsid',
1498             'value' => $draftidattach,
1499         );
1501         // Update the assessment.
1502         $result = mod_workshop_external::update_assessment($assessmentid, $data);
1503         $result = external_api::clean_returnvalue(mod_workshop_external::update_assessment_returns(), $result);
1504         $this->assertEquals(100, $result['rawgrade']);
1505         $this->assertTrue($result['status']);
1507         // Get the assessment and check it was updated properly.
1508         $result = mod_workshop_external::get_assessment($assessmentid);
1509         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1510         $this->assertEquals(100, $result['assessment']['grade']);
1511         $this->assertEquals($this->student->id, $result['assessment']['reviewerid']);
1512         $this->assertEquals('Feedback for the author', $result['assessment']['feedbackauthor']);
1513         $this->assertCount(1, $result['assessment']['feedbackcontentfiles']);
1514         $this->assertCount(1, $result['assessment']['feedbackattachmentfiles']);
1516         // Now, get again the form and check we received the data we already sent.
1517         $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1518         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1519         foreach ($result['current'] as $currentdata) {
1520             if (strpos($currentdata['name'], 'peercomment__idx_') === 0) {
1521                 $this->assertEquals('Some content', $currentdata['value']);
1522             } else if (strpos($currentdata['name'], 'grade__idx_') === 0) {
1523                 $this->assertEquals(25, (int) $currentdata['value']);
1524             }
1525         }
1526     }
1528     /**
1529      * Test get_grades.
1530      */
1531     public function test_get_grades() {
1532         global $DB;
1534         $timenow = time();
1535         $submissiongrade = array(
1536             'userid' => $this->student->id,
1537             'rawgrade' => 40,
1538             'feedback' => '',
1539             'feedbackformat' => 1,
1540             'datesubmitted' => $timenow,
1541             'dategraded' => $timenow,
1542         );
1543         $assessmentgrade = array(
1544             'userid' => $this->student->id,
1545             'rawgrade' => 10,
1546             'feedback' => '',
1547             'feedbackformat' => 1,
1548             'datesubmitted' => $timenow,
1549             'dategraded' => $timenow,
1550         );
1552         workshop_grade_item_update($this->workshop, (object) $submissiongrade, (object) $assessmentgrade);
1554         // First retrieve my grades.
1555         $this->setUser($this->student);
1556         $result = mod_workshop_external::get_grades($this->workshop->id);
1557         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_returns(), $result);
1558         $this->assertCount(0, $result['warnings']);
1559         $this->assertEquals($assessmentgrade['rawgrade'], $result['assessmentrawgrade']);
1560         $this->assertEquals($submissiongrade['rawgrade'], $result['submissionrawgrade']);
1561         $this->assertFalse($result['assessmentgradehidden']);
1562         $this->assertFalse($result['submissiongradehidden']);
1563         $this->assertEquals($assessmentgrade['rawgrade'] . ".00 / 20.00", $result['assessmentlongstrgrade']);
1564         $this->assertEquals($submissiongrade['rawgrade'] . ".00 / 80.00", $result['submissionlongstrgrade']);
1566         // Second, teacher retrieve user grades.
1567         $this->setUser($this->teacher);
1568         $result = mod_workshop_external::get_grades($this->workshop->id, $this->student->id);
1569         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_returns(), $result);
1570         $this->assertCount(0, $result['warnings']);
1571         $this->assertEquals($assessmentgrade['rawgrade'], $result['assessmentrawgrade']);
1572         $this->assertEquals($submissiongrade['rawgrade'], $result['submissionrawgrade']);
1573         $this->assertFalse($result['assessmentgradehidden']);
1574         $this->assertFalse($result['submissiongradehidden']);
1575         $this->assertEquals($assessmentgrade['rawgrade'] . ".00 / 20.00", $result['assessmentlongstrgrade']);
1576         $this->assertEquals($submissiongrade['rawgrade'] . ".00 / 80.00", $result['submissionlongstrgrade']);
1577     }
1579     /**
1580      * Test get_grades_other_student.
1581      */
1582     public function test_get_grades_other_student() {
1583         global $DB;
1585         // Create the submission that will be deleted.
1586         $submissionid = $this->create_test_submission($this->student);
1588         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
1589         $this->setUser($this->anotherstudentg1);
1590         $this->expectException('moodle_exception');
1591         mod_workshop_external::get_grades($this->workshop->id, $this->student->id);
1592     }
1594     /**
1595      * Test evaluate_assessment.
1596      */
1597     public function test_evaluate_assessment() {
1598         global $DB;
1600         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1601         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1602         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1603             'weight' => 3,
1604             'grade' => 95,
1605         ));
1607         $this->setUser($this->teacher);
1608         $feedbacktext = 'The feedback';
1609         $feedbackformat = FORMAT_MOODLE;
1610         $weight = 25;
1611         $gradinggradeover = 10;
1612         $result = mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight,
1613             $gradinggradeover);
1614         $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_assessment_returns(), $result);
1615         $this->assertTrue($result['status']);
1617         $assessment = $DB->get_record('workshop_assessments', array('id' => $assessmentid));
1618         $this->assertEquals('The feedback', $assessment->feedbackreviewer);
1619         $this->assertEquals(25, $assessment->weight);
1620     }
1622     /**
1623      * Test evaluate_assessment_ignore_parameters.
1624      */
1625     public function test_evaluate_assessment_ignore_parameters() {
1626         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1627         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1628         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1629             'weight' => 3,
1630             'grade' => 95,
1631         ));
1633         assign_capability('mod/workshop:allocate', CAP_PROHIBIT, $this->teacherrole->id, $this->context->id);
1634         // Empty all the caches that may be affected  by this change.
1635         accesslib_clear_all_caches_for_unit_testing();
1637         $this->setUser($this->teacher);
1638         $feedbacktext = 'The feedback';
1639         $feedbackformat = FORMAT_MOODLE;
1640         $weight = 25;
1641         $gradinggradeover = 1000;
1642         $result = mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight,
1643             $gradinggradeover);
1644         $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_assessment_returns(), $result);
1645         $this->assertTrue($result['status']);
1647         $result = mod_workshop_external::get_assessment($assessmentid);
1648         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1649         $this->assertNotEquals(25, $result['assessment']['weight']);
1650     }
1652     /**
1653      * Test evaluate_assessment_no_permissions.
1654      */
1655     public function test_evaluate_assessment_no_permissions() {
1656         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1657         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1658         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1659             'weight' => 3,
1660             'grade' => 95,
1661         ));
1663         $this->setUser($this->student);
1664         $feedbacktext = 'The feedback';
1665         $feedbackformat = FORMAT_MOODLE;
1666         $weight = 25;
1667         $gradinggradeover = 50;
1668         $this->expectException('moodle_exception');
1669         mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight, $gradinggradeover);
1670     }
1672     /**
1673      * Test get_grades_report.
1674      */
1675     public function test_get_grades_report() {
1676         global $DB;
1678         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1679         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1680         $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1681         $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
1683         $assessmentid1 = $workshopgenerator->create_assessment($submissionid2, $this->student->id, array(
1684             'weight' => 100,
1685             'grade' => 50,
1686         ));
1687         $assessmentid2 = $workshopgenerator->create_assessment($submissionid1, $this->anotherstudentg1->id, array(
1688             'weight' => 100,
1689             'grade' => 55,
1690         ));
1692         $DB->set_field('workshop', 'phase', workshop::PHASE_CLOSED, array('id' => $this->workshop->id));
1693         $this->setUser($this->teacher);
1694         $result = mod_workshop_external::get_grades_report($this->workshop->id);
1695         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1696         $this->assertEquals(3, $result['report']['totalcount']); // Expect 3 potential submissions.
1698         foreach ($result['report']['grades'] as $grade) {
1699             if ($grade['userid'] == $this->student->id) {
1700                 $this->assertEquals($this->anotherstudentg1->id, $grade['reviewedby'][0]['userid']); // Check reviewer.
1701                 $this->assertEquals($this->anotherstudentg1->id, $grade['reviewerof'][0]['userid']); // Check reviewer.
1702                 $this->assertEquals($workshop->real_grade(50), $grade['reviewerof'][0]['grade']); // Check grade (converted).
1703                 $this->assertEquals($workshop->real_grade(55), $grade['reviewedby'][0]['grade']); // Check grade (converted).
1704             } else if ($grade['userid'] == $this->anotherstudentg1->id) {
1705                 $this->assertEquals($this->student->id, $grade['reviewedby'][0]['userid']); // Check reviewer.
1706                 $this->assertEquals($this->student->id, $grade['reviewerof'][0]['userid']); // Check reviewer.
1707                 $this->assertEquals($workshop->real_grade(55), $grade['reviewerof'][0]['grade']); // Check grade (converted).
1708                 $this->assertEquals($workshop->real_grade(50), $grade['reviewedby'][0]['grade']); // Check grade (converted).
1709             }
1710         }
1711         // Now check pagination.
1712         $result = mod_workshop_external::get_grades_report($this->workshop->id, 0, 'lastname', 'ASC', 0, 1);
1713         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1714         $this->assertEquals(3, $result['report']['totalcount']); // Expect the total count.
1715         $this->assertCount(1, $result['report']['grades']);
1717         // Groups filtering.
1718         $result = mod_workshop_external::get_grades_report($this->workshop->id, $this->group1->id);
1719         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1720         $this->assertEquals(2, $result['report']['totalcount']); // Expect the group count.
1721     }
1723     /**
1724      * Test get_grades_report_invalid_phase.
1725      */
1726     public function test_get_grades_report_invalid_phase() {
1727         $this->setUser($this->teacher);
1728         $this->expectException('moodle_exception');
1729         $this->expectExceptionMessage(get_string('nothingfound', 'workshop'));
1730         mod_workshop_external::get_grades_report($this->workshop->id);
1731     }
1733     /**
1734      * Test get_grades_report_missing_permissions.
1735      */
1736     public function test_get_grades_report_missing_permissions() {
1737         $this->setUser($this->student);
1738         $this->expectException('required_capability_exception');
1739         mod_workshop_external::get_grades_report($this->workshop->id);
1740     }
1742     /**
1743      * Test test_view_submission.
1744      */
1745     public function test_view_submission() {
1747         // Create a couple of submissions with files.
1748         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
1750         // Trigger and capture the event.
1751         $sink = $this->redirectEvents();
1753         $this->setUser($this->student);
1754         $result = mod_workshop_external::view_submission($firstsubmissionid);
1755         $result = external_api::clean_returnvalue(mod_workshop_external::view_submission_returns(), $result);
1757         $events = $sink->get_events();
1758         $this->assertCount(1, $events);
1759         $event = array_shift($events);
1761         // Checking that the event contains the expected values.
1762         $this->assertInstanceOf('\mod_workshop\event\submission_viewed', $event);
1763         $this->assertEquals($this->context, $event->get_context());
1764         $moodleworkshop = new \moodle_url('/mod/workshop/submission.php', array('id' => $firstsubmissionid,
1765             'cmid' => $this->cm->id));
1766         $this->assertEquals($moodleworkshop, $event->get_url());
1767         $this->assertEventContextNotUsed($event);
1768         $this->assertNotEmpty($event->get_name());
1770     }