Merge branch 'MDL-60249-master' of git://github.com/damyon/moodle
[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() {
127         // Create additional course.
128         $course2 = self::getDataGenerator()->create_course();
130         // Second workshop.
131         $record = new stdClass();
132         $record->course = $course2->id;
133         $workshop2 = self::getDataGenerator()->create_module('workshop', $record);
135         // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
136         $enrol = enrol_get_plugin('manual');
137         $enrolinstances = enrol_get_instances($course2->id, true);
138         foreach ($enrolinstances as $courseenrolinstance) {
139             if ($courseenrolinstance->enrol == "manual") {
140                 $instance2 = $courseenrolinstance;
141                 break;
142             }
143         }
144         $enrol->enrol_user($instance2, $this->student->id, $this->studentrole->id);
146         self::setUser($this->student);
148         $returndescription = mod_workshop_external::get_workshops_by_courses_returns();
150         // Create what we expect to be returned when querying the two courses.
151         $properties = workshop_summary_exporter::read_properties_definition();
152         $expectedfields = array_keys($properties);
154         // Add expected coursemodule and data.
155         $workshop1 = $this->workshop;
156         $workshop1->coursemodule = $workshop1->cmid;
157         $workshop1->introformat = 1;
158         $workshop1->introfiles = [];
159         $workshop1->instructauthorsfiles = [];
160         $workshop1->instructauthorsformat = 1;
161         $workshop1->instructreviewersfiles = [];
162         $workshop1->instructreviewersformat = 1;
163         $workshop1->conclusionfiles = [];
164         $workshop1->conclusionformat = 1;
166         $workshop2->coursemodule = $workshop2->cmid;
167         $workshop2->introformat = 1;
168         $workshop2->introfiles = [];
169         $workshop2->instructauthorsfiles = [];
170         $workshop2->instructauthorsformat = 1;
171         $workshop2->instructreviewersfiles = [];
172         $workshop2->instructreviewersformat = 1;
173         $workshop2->conclusionfiles = [];
174         $workshop2->conclusionformat = 1;
176         foreach ($expectedfields as $field) {
177             if (!empty($properties[$field]) && $properties[$field]['type'] == PARAM_BOOL) {
178                 $workshop1->{$field} = (bool) $workshop1->{$field};
179                 $workshop2->{$field} = (bool) $workshop2->{$field};
180             }
181             $expected1[$field] = $workshop1->{$field};
182             $expected2[$field] = $workshop2->{$field};
183         }
185         $expectedworkshops = array($expected2, $expected1);
187         // Call the external function passing course ids.
188         $result = mod_workshop_external::get_workshops_by_courses(array($course2->id, $this->course->id));
189         $result = external_api::clean_returnvalue($returndescription, $result);
191         $this->assertEquals($expectedworkshops, $result['workshops']);
192         $this->assertCount(0, $result['warnings']);
194         // Call the external function without passing course id.
195         $result = mod_workshop_external::get_workshops_by_courses();
196         $result = external_api::clean_returnvalue($returndescription, $result);
197         $this->assertEquals($expectedworkshops, $result['workshops']);
198         $this->assertCount(0, $result['warnings']);
200         // Unenrol user from second course and alter expected workshops.
201         $enrol->unenrol_user($instance2, $this->student->id);
202         array_shift($expectedworkshops);
204         // Call the external function without passing course id.
205         $result = mod_workshop_external::get_workshops_by_courses();
206         $result = external_api::clean_returnvalue($returndescription, $result);
207         $this->assertEquals($expectedworkshops, $result['workshops']);
209         // Call for the second course we unenrolled the user from, expected warning.
210         $result = mod_workshop_external::get_workshops_by_courses(array($course2->id));
211         $this->assertCount(1, $result['warnings']);
212         $this->assertEquals('1', $result['warnings'][0]['warningcode']);
213         $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
214     }
216     /**
217      * Test mod_workshop_get_workshop_access_information for students.
218      */
219     public function test_mod_workshop_get_workshop_access_information_student() {
221         self::setUser($this->student);
222         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
223         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
224         // Check default values for capabilities.
225         $enabledcaps = array('canpeerassess', 'cansubmit', 'canview', 'canviewauthornames', 'canviewauthorpublished',
226             'canviewpublishedsubmissions', 'canexportsubmissions');
228         foreach ($result as $capname => $capvalue) {
229             if (strpos($capname, 'can') !== 0) {
230                 continue;
231             }
232             if (in_array($capname, $enabledcaps)) {
233                 $this->assertTrue($capvalue);
234             } else {
235                 $this->assertFalse($capvalue);
236             }
237         }
238         // Now, unassign some capabilities.
239         unassign_capability('mod/workshop:peerassess', $this->studentrole->id);
240         unassign_capability('mod/workshop:submit', $this->studentrole->id);
241         unset($enabledcaps[0]);
242         unset($enabledcaps[1]);
243         accesslib_clear_all_caches_for_unit_testing();
245         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
246         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
247         foreach ($result as $capname => $capvalue) {
248             if (strpos($capname, 'can') !== 0) {
249                 continue;
250             }
251             if (in_array($capname, $enabledcaps)) {
252                 $this->assertTrue($capvalue);
253             } else {
254                 $this->assertFalse($capvalue);
255             }
256         }
258         // Now, specific functionalities.
259         $this->assertFalse($result['creatingsubmissionallowed']);
260         $this->assertFalse($result['modifyingsubmissionallowed']);
261         $this->assertFalse($result['assessingallowed']);
262         $this->assertFalse($result['assessingexamplesallowed']);
263         $this->assertTrue($result['examplesassessedbeforesubmission']);
264         $this->assertTrue($result['examplesassessedbeforeassessment']);
266         // Switch phase.
267         $workshop = new workshop($this->workshop, $this->cm, $this->course);
268         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
269         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
270         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
272         $this->assertTrue($result['creatingsubmissionallowed']);
273         $this->assertTrue($result['modifyingsubmissionallowed']);
274         $this->assertFalse($result['assessingallowed']);
275         $this->assertFalse($result['assessingexamplesallowed']);
276         $this->assertTrue($result['examplesassessedbeforesubmission']);
277         $this->assertTrue($result['examplesassessedbeforeassessment']);
279         // Switch to next (to assessment).
280         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
281         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
282         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
284         $this->assertFalse($result['creatingsubmissionallowed']);
285         $this->assertFalse($result['modifyingsubmissionallowed']);
286         $this->assertTrue($result['assessingallowed']);
287         $this->assertFalse($result['assessingexamplesallowed']);
288         $this->assertTrue($result['examplesassessedbeforesubmission']);
289         $this->assertTrue($result['examplesassessedbeforeassessment']);
290     }
292     /**
293      * Test mod_workshop_get_workshop_access_information for teachers.
294      */
295     public function test_mod_workshop_get_workshop_access_information_teacher() {
297         self::setUser($this->teacher);
298         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
299         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
300         // Check default values.
301         $disabledcaps = array('canpeerassess', 'cansubmit');
303         foreach ($result as $capname => $capvalue) {
304             if (strpos($capname, 'can') !== 0) {
305                 continue;
306             }
307             if (in_array($capname, $disabledcaps)) {
308                 $this->assertFalse($capvalue);
309             } else {
310                 $this->assertTrue($capvalue);
311             }
312         }
314         // Now, specific functionalities.
315         $this->assertFalse($result['creatingsubmissionallowed']);
316         $this->assertFalse($result['modifyingsubmissionallowed']);
317         $this->assertFalse($result['assessingallowed']);
318         $this->assertFalse($result['assessingexamplesallowed']);
319     }
321     /**
322      * Test mod_workshop_get_user_plan for students.
323      */
324     public function test_mod_workshop_get_user_plan_student() {
326         self::setUser($this->student);
327         $result = mod_workshop_external::get_user_plan($this->workshop->id);
328         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
330         $this->assertCount(0, $result['userplan']['examples']);  // No examples given.
331         $this->assertCount(5, $result['userplan']['phases']);  // Always 5 phases.
332         $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']);  // First phase always setup.
333         $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
335         // Switch phase.
336         $workshop = new workshop($this->workshop, $this->cm, $this->course);
337         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
339         $result = mod_workshop_external::get_user_plan($this->workshop->id);
340         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
342         $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
343         $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
344     }
346     /**
347      * Test mod_workshop_get_user_plan for teachers.
348      */
349     public function test_mod_workshop_get_user_plan_teacher() {
351         self::setUser($this->teacher);
352         $result = mod_workshop_external::get_user_plan($this->workshop->id);
353         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
355         $this->assertCount(0, $result['userplan']['examples']);  // No examples given.
356         $this->assertCount(5, $result['userplan']['phases']);  // Always 5 phases.
357         $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']);  // First phase always setup.
358         $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
359         $this->assertCount(4, $result['userplan']['phases'][0]['tasks']);  // For new empty workshops, always 4 tasks.
361         foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
362             if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'editform') {
363                 $this->assertEquals(1, $task['completed']);
364             } else {
365                 $this->assertEmpty($task['completed']);
366             }
367         }
369         // Do some of the tasks asked - switch phase.
370         $workshop = new workshop($this->workshop, $this->cm, $this->course);
371         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
373         $result = mod_workshop_external::get_user_plan($this->workshop->id);
374         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
375         foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
376             if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'editform' ||
377                     $task['code'] == 'switchtonextphase') {
378                 $this->assertEquals(1, $task['completed']);
379             } else {
380                 $this->assertEmpty($task['completed']);
381             }
382         }
384         $result = mod_workshop_external::get_user_plan($this->workshop->id);
385         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
387         $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
388         $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
389     }
391     /**
392      * Test test_view_workshop invalid id.
393      */
394     public function test_view_workshop_invalid_id() {
395         $this->expectException('moodle_exception');
396         mod_workshop_external::view_workshop(0);
397     }
399     /**
400      * Test test_view_workshop user not enrolled.
401      */
402     public function test_view_workshop_user_not_enrolled() {
403         // Test not-enrolled user.
404         $usernotenrolled = self::getDataGenerator()->create_user();
405         $this->setUser($usernotenrolled);
406         $this->expectException('moodle_exception');
407         mod_workshop_external::view_workshop($this->workshop->id);
408     }
410     /**
411      * Test test_view_workshop user student.
412      */
413     public function test_view_workshop_user_student() {
414         // Test user with full capabilities.
415         $this->setUser($this->student);
417         // Trigger and capture the event.
418         $sink = $this->redirectEvents();
420         $result = mod_workshop_external::view_workshop($this->workshop->id);
421         $result = external_api::clean_returnvalue(mod_workshop_external::view_workshop_returns(), $result);
422         $this->assertTrue($result['status']);
424         $events = $sink->get_events();
425         $this->assertCount(1, $events);
426         $event = array_shift($events);
428         // Checking that the event contains the expected values.
429         $this->assertInstanceOf('\mod_workshop\event\course_module_viewed', $event);
430         $this->assertEquals($this->context, $event->get_context());
431         $moodleworkshop = new \moodle_url('/mod/workshop/view.php', array('id' => $this->cm->id));
432         $this->assertEquals($moodleworkshop, $event->get_url());
433         $this->assertEventContextNotUsed($event);
434         $this->assertNotEmpty($event->get_name());
435     }
437     /**
438      * Test test_view_workshop user missing capabilities.
439      */
440     public function test_view_workshop_user_missing_capabilities() {
441         // Test user with no capabilities.
442         // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
443         assign_capability('mod/workshop:view', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
444         // Empty all the caches that may be affected  by this change.
445         accesslib_clear_all_caches_for_unit_testing();
446         course_modinfo::clear_instance_cache();
448         $this->setUser($this->student);
449         $this->expectException('moodle_exception');
450         mod_workshop_external::view_workshop($this->workshop->id);
451     }
453     /**
454      * Test test_add_submission.
455      */
456     public function test_add_submission() {
457         $fs = get_file_storage();
459         // Test user with full capabilities.
460         $this->setUser($this->student);
462         $title = 'Submission title';
463         $content = 'Submission contents';
465         // Create a file in a draft area for inline attachments.
466         $draftidinlineattach = file_get_unused_draft_itemid();
467         $usercontext = context_user::instance($this->student->id);
468         $filenameimg = 'shouldbeanimage.txt';
469         $filerecordinline = array(
470             'contextid' => $usercontext->id,
471             'component' => 'user',
472             'filearea'  => 'draft',
473             'itemid'    => $draftidinlineattach,
474             'filepath'  => '/',
475             'filename'  => $filenameimg,
476         );
477         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
479         // Create a file in a draft area for regular attachments.
480         $draftidattach = file_get_unused_draft_itemid();
481         $filerecordattach = $filerecordinline;
482         $attachfilename = 'attachment.txt';
483         $filerecordattach['filename'] = $attachfilename;
484         $filerecordattach['itemid'] = $draftidattach;
485         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
487         // Switch to submission phase.
488         $workshop = new workshop($this->workshop, $this->cm, $this->course);
489         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
491         $result = mod_workshop_external::add_submission($this->workshop->id, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
492             $draftidattach);
493         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
494         $this->assertEmpty($result['warnings']);
496         // Check submission created.
497         $submission = $workshop->get_submission_by_author($this->student->id);
498         $this->assertTrue($result['status']);
499         $this->assertEquals($result['submissionid'], $submission->id);
500         $this->assertEquals($title, $submission->title);
501         $this->assertEquals($content, $submission->content);
503         // Check files.
504         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_content', $submission->id);
505         $this->assertCount(2, $contentfiles);
506         foreach ($contentfiles as $file) {
507             if ($file->is_directory()) {
508                 continue;
509             } else {
510                 $this->assertEquals($filenameimg, $file->get_filename());
511             }
512         }
513         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_attachment', $submission->id);
514         $this->assertCount(2, $contentfiles);
515         foreach ($contentfiles as $file) {
516             if ($file->is_directory()) {
517                 continue;
518             } else {
519                 $this->assertEquals($attachfilename, $file->get_filename());
520             }
521         }
522     }
524     /**
525      * Test test_add_submission invalid phase.
526      */
527     public function test_add_submission_invalid_phase() {
528         $this->setUser($this->student);
530         $this->expectException('moodle_exception');
531         mod_workshop_external::add_submission($this->workshop->id, 'Test');
532     }
534     /**
535      * Test test_add_submission empty title.
536      */
537     public function test_add_submission_empty_title() {
538         $this->setUser($this->student);
540         // Switch to submission phase.
541         $workshop = new workshop($this->workshop, $this->cm, $this->course);
542         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
544         $this->expectException('moodle_exception');
545         mod_workshop_external::add_submission($this->workshop->id, '');
546     }
548     /**
549      * Test test_add_submission already added.
550      */
551     public function test_add_submission_already_added() {
552         $this->setUser($this->student);
554         // Switch to submission phase.
555         $workshop = new workshop($this->workshop, $this->cm, $this->course);
556         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
558         // Create the submission.
559         $result = mod_workshop_external::add_submission($this->workshop->id, 'My submission');
560         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
562         // Try to create it again.
563         $result = mod_workshop_external::add_submission($this->workshop->id, 'My submission');
564         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
565         $this->assertFalse($result['status']);
566         $this->assertArrayNotHasKey('submissionid', $result);
567         $this->assertCount(2, $result['warnings']);
568         $this->assertEquals('fielderror', $result['warnings'][0]['warningcode']);
569         $this->assertEquals('content_editor', $result['warnings'][0]['item']);
570         $this->assertEquals('fielderror', $result['warnings'][1]['warningcode']);
571         $this->assertEquals('attachment_filemanager', $result['warnings'][1]['item']);
572     }
574     /**
575      * Helper method to create a submission for testing for the given user.
576      *
577      * @param int $user the submission will be created by this student.
578      * @return int the submission id
579      */
580     protected function create_test_submission($user) {
581         // Test user with full capabilities.
582         $this->setUser($user);
584         $title = 'Submission title';
585         $content = 'Submission contents';
587         // Create a file in a draft area for inline attachments.
588         $fs = get_file_storage();
589         $draftidinlineattach = file_get_unused_draft_itemid();
590         $usercontext = context_user::instance($this->student->id);
591         $filenameimg = 'shouldbeanimage.txt';
592         $filerecordinline = array(
593             'contextid' => $usercontext->id,
594             'component' => 'user',
595             'filearea'  => 'draft',
596             'itemid'    => $draftidinlineattach,
597             'filepath'  => '/',
598             'filename'  => $filenameimg,
599         );
600         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
602         // Create a file in a draft area for regular attachments.
603         $draftidattach = file_get_unused_draft_itemid();
604         $filerecordattach = $filerecordinline;
605         $attachfilename = 'attachment.txt';
606         $filerecordattach['filename'] = $attachfilename;
607         $filerecordattach['itemid'] = $draftidattach;
608         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
610         // Switch to submission phase.
611         $workshop = new workshop($this->workshop, $this->cm, $this->course);
612         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
614         $result = mod_workshop_external::add_submission($this->workshop->id, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
615             $draftidattach);
616         return $result['submissionid'];
617     }
619     /**
620      * Test test_update_submission.
621      */
622     public function test_update_submission() {
624         // Create the submission that will be updated.
625         $submissionid = $this->create_test_submission($this->student);
627         // Test user with full capabilities.
628         $this->setUser($this->student);
630         $title = 'Submission new title';
631         $content = 'Submission new contents';
633         // Create a different file in a draft area for inline attachments.
634         $fs = get_file_storage();
635         $draftidinlineattach = file_get_unused_draft_itemid();
636         $usercontext = context_user::instance($this->student->id);
637         $filenameimg = 'shouldbeanimage_new.txt';
638         $filerecordinline = array(
639             'contextid' => $usercontext->id,
640             'component' => 'user',
641             'filearea'  => 'draft',
642             'itemid'    => $draftidinlineattach,
643             'filepath'  => '/',
644             'filename'  => $filenameimg,
645         );
646         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
648         // Create a different file in a draft area for regular attachments.
649         $draftidattach = file_get_unused_draft_itemid();
650         $filerecordattach = $filerecordinline;
651         $attachfilename = 'attachment_new.txt';
652         $filerecordattach['filename'] = $attachfilename;
653         $filerecordattach['itemid'] = $draftidattach;
654         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
656         $result = mod_workshop_external::update_submission($submissionid, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
657             $draftidattach);
658         $result = external_api::clean_returnvalue(mod_workshop_external::update_submission_returns(), $result);
659         $this->assertEmpty($result['warnings']);
661         // Check submission updated.
662         $workshop = new workshop($this->workshop, $this->cm, $this->course);
663         $submission = $workshop->get_submission_by_id($submissionid);
664         $this->assertTrue($result['status']);
665         $this->assertEquals($title, $submission->title);
666         $this->assertEquals($content, $submission->content);
668         // Check files.
669         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_content', $submission->id);
670         $this->assertCount(2, $contentfiles);
671         foreach ($contentfiles as $file) {
672             if ($file->is_directory()) {
673                 continue;
674             } else {
675                 $this->assertEquals($filenameimg, $file->get_filename());
676             }
677         }
678         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_attachment', $submission->id);
679         $this->assertCount(2, $contentfiles);
680         foreach ($contentfiles as $file) {
681             if ($file->is_directory()) {
682                 continue;
683             } else {
684                 $this->assertEquals($attachfilename, $file->get_filename());
685             }
686         }
687     }
689     /**
690      * Test test_update_submission belonging to other user.
691      */
692     public function test_update_submission_of_other_user() {
693         // Create the submission that will be updated.
694         $submissionid = $this->create_test_submission($this->student);
696         $this->setUser($this->teacher);
698         $this->expectException('moodle_exception');
699         mod_workshop_external::update_submission($submissionid, 'Test');
700     }
702     /**
703      * Test test_update_submission invalid phase.
704      */
705     public function test_update_submission_invalid_phase() {
706         // Create the submission that will be updated.
707         $submissionid = $this->create_test_submission($this->student);
709         $this->setUser($this->student);
711         // Switch to assessment phase.
712         $workshop = new workshop($this->workshop, $this->cm, $this->course);
713         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
715         $this->expectException('moodle_exception');
716         mod_workshop_external::update_submission($submissionid, 'Test');
717     }
719     /**
720      * Test test_update_submission empty title.
721      */
722     public function test_update_submission_empty_title() {
723         // Create the submission that will be updated.
724         $submissionid = $this->create_test_submission($this->student);
726         $this->setUser($this->student);
728         $this->expectException('moodle_exception');
729         mod_workshop_external::update_submission($submissionid, '');
730     }
732     /**
733      * Test test_delete_submission.
734      */
735     public function test_delete_submission() {
737         // Create the submission that will be deleted.
738         $submissionid = $this->create_test_submission($this->student);
740         $this->setUser($this->student);
742         // Trigger and capture the event.
743         $sink = $this->redirectEvents();
745         $result = mod_workshop_external::delete_submission($submissionid);
746         $result = external_api::clean_returnvalue(mod_workshop_external::delete_submission_returns(), $result);
747         $this->assertEmpty($result['warnings']);
748         $this->assertTrue($result['status']);
749         $workshop = new workshop($this->workshop, $this->cm, $this->course);
750         $submission = $workshop->get_submission_by_author($this->student->id);
751         $this->assertFalse($submission);
753         $events = $sink->get_events();
754         $this->assertCount(1, $events);
755         $event = array_shift($events);
757         // Checking event.
758         $this->assertInstanceOf('\mod_workshop\event\submission_deleted', $event);
759         $this->assertEquals($this->context, $event->get_context());
760     }
762     /**
763      * Test test_delete_submission_with_assessments.
764      */
765     public function test_delete_submission_with_assessments() {
767         // Create the submission that will be deleted.
768         $submissionid = $this->create_test_submission($this->student);
770         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
771         $workshopgenerator->create_assessment($submissionid, $this->teacher->id, array(
772             'weight' => 3,
773             'grade' => 95.00000,
774         ));
776         $this->setUser($this->student);
777         $this->expectException('moodle_exception');
778         mod_workshop_external::delete_submission($submissionid);
779     }
781     /**
782      * Test test_delete_submission_invalid_phase.
783      */
784     public function test_delete_submission_invalid_phase() {
786         // Create the submission that will be deleted.
787         $submissionid = $this->create_test_submission($this->student);
789         // Switch to assessment phase.
790         $workshop = new workshop($this->workshop, $this->cm, $this->course);
791         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
793         $this->setUser($this->student);
794         $this->expectException('moodle_exception');
795         mod_workshop_external::delete_submission($submissionid);
796     }
798     /**
799      * Test test_delete_submission_as_teacher.
800      */
801     public function test_delete_submission_as_teacher() {
803         // Create the submission that will be deleted.
804         $submissionid = $this->create_test_submission($this->student);
806         $this->setUser($this->teacher);
807         $result = mod_workshop_external::delete_submission($submissionid);
808         $result = external_api::clean_returnvalue(mod_workshop_external::delete_submission_returns(), $result);
809         $this->assertEmpty($result['warnings']);
810         $this->assertTrue($result['status']);
811     }
813     /**
814      * Test test_delete_submission_other_user.
815      */
816     public function test_delete_submission_other_user() {
818         $anotheruser = self::getDataGenerator()->create_user();
819         $this->getDataGenerator()->enrol_user($anotheruser->id, $this->course->id, $this->studentrole->id, 'manual');
820         // Create the submission that will be deleted.
821         $submissionid = $this->create_test_submission($this->student);
823         $this->setUser($anotheruser);
824         $this->expectException('moodle_exception');
825         mod_workshop_external::delete_submission($submissionid);
826     }
828     /**
829      * Test test_get_submissions_student.
830      */
831     public function test_get_submissions_student() {
833         // Create a couple of submissions with files.
834         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
835         $secondsubmissionid = $this->create_test_submission($this->anotherstudentg1->id);
837         $this->setUser($this->student);
838         $result = mod_workshop_external::get_submissions($this->workshop->id);
839         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
840         // We should get just our submission.
841         $this->assertCount(1, $result['submissions']);
842         $this->assertEquals(1, $result['totalcount']);
843         $this->assertEquals($firstsubmissionid, $result['submissions'][0]['id']);
844         $this->assertCount(1, $result['submissions'][0]['contentfiles']); // Check we retrieve submission text files.
845         $this->assertCount(1, $result['submissions'][0]['attachmentfiles']); // Check we retrieve attachment files.
846         // We shoul not see the grade or feedback information.
847         $properties = submission_exporter::properties_definition();
848         foreach ($properties as $attribute => $settings) {
849             if (!empty($settings['optional'])) {
850                 if (isset($result['submissions'][0][$attribute])) {
851                     echo "error $attribute";
852                 }
853                 $this->assertFalse(isset($result['submissions'][0][$attribute]));
854             }
855         }
856     }
858     /**
859      * Test test_get_submissions_published_student.
860      */
861     public function test_get_submissions_published_student() {
863         $workshop = new workshop($this->workshop, $this->cm, $this->course);
864         $workshop->switch_phase(workshop::PHASE_CLOSED);
865         // Create a couple of submissions with files.
866         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
867         $submission = array('published' => 1);
868         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id, $submission);
870         $this->setUser($this->student);
871         $result = mod_workshop_external::get_submissions($this->workshop->id);
872         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
873         // We should get just our submission.
874         $this->assertCount(1, $result['submissions']);
875         $this->assertEquals(1, $result['totalcount']);
876         $this->assertEquals($submissionid, $result['submissions'][0]['id']);
878         // Check with group restrictions.
879         $this->setUser($this->anotherstudentg2);
880         $result = mod_workshop_external::get_submissions($this->workshop->id);
881         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
882         $this->assertCount(0, $result['submissions']);  // I can't see other users in separated groups.
883         $this->assertEquals(0, $result['totalcount']);
884     }
886     /**
887      * Test test_get_submissions_from_student_with_feedback_from_teacher.
888      */
889     public function test_get_submissions_from_student_with_feedback_from_teacher() {
890         global $DB;
892         // Create a couple of submissions with files.
893         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
894         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
895         // Create teacher feedback for submission.
896         $record = new stdclass();
897         $record->id = $submissionid;
898         $record->gradeover = 9;
899         $record->gradeoverby = $this->teacher->id;
900         $record->feedbackauthor = 'Hey';
901         $record->feedbackauthorformat = FORMAT_MOODLE;
902         $record->published = 1;
903         $DB->update_record('workshop_submissions', $record);
905         // Remove teacher caps.
906         assign_capability('mod/workshop:viewallsubmissions', CAP_PROHIBIT, $this->teacher->id, $this->context->id);
907         // Empty all the caches that may be affected  by this change.
908         accesslib_clear_all_caches_for_unit_testing();
909         course_modinfo::clear_instance_cache();
911         $this->setUser($this->teacher);
912         $result = mod_workshop_external::get_submissions($this->workshop->id, $this->student->id);
913         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
914         // We should get just our submission.
915         $this->assertEquals(1, $result['totalcount']);
916         $this->assertEquals($submissionid, $result['submissions'][0]['id']);
917     }
919     /**
920      * Test test_get_submissions_from_students_as_teacher.
921      */
922     public function test_get_submissions_from_students_as_teacher() {
924         // Create a couple of submissions with files.
925         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
926         $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
927         $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
928         $submissionid3 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg2->id);
930         $this->setUser($this->teacher);
931         $result = mod_workshop_external::get_submissions($this->workshop->id); // Get all.
932         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
933         $this->assertEquals(3, $result['totalcount']);
934         $this->assertCount(3, $result['submissions']);
936         $result = mod_workshop_external::get_submissions($this->workshop->id, 0, 0, 0, 2); // Check pagination.
937         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
938         $this->assertEquals(3, $result['totalcount']);
939         $this->assertCount(2, $result['submissions']);
941         $result = mod_workshop_external::get_submissions($this->workshop->id, 0, $this->group2->id); // Get group 2.
942         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
943         $this->assertEquals(1, $result['totalcount']);
944         $this->assertCount(1, $result['submissions']);
945         $this->assertEquals($submissionid3, $result['submissions'][0]['id']);
947         $result = mod_workshop_external::get_submissions($this->workshop->id, $this->anotherstudentg1->id); // Get one.
948         $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
949         $this->assertEquals(1, $result['totalcount']);
950         $this->assertEquals($submissionid2, $result['submissions'][0]['id']);
951     }
953     /**
954      * Test test_get_submission_student.
955      */
956     public function test_get_submission_student() {
958         // Create a couple of submissions with files.
959         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
961         $workshop = new workshop($this->workshop, $this->cm, $this->course);
962         $workshop->switch_phase(workshop::PHASE_CLOSED);
963         $this->setUser($this->student);
964         $result = mod_workshop_external::get_submission($firstsubmissionid);
965         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
966         $this->assertEquals($firstsubmissionid, $result['submission']['id']);
967         $this->assertCount(1, $result['submission']['contentfiles']); // Check we retrieve submission text files.
968         $this->assertCount(1, $result['submission']['attachmentfiles']); // Check we retrieve attachment files.
969         $this->assertArrayHasKey('feedbackauthor', $result['submission']);
970         $this->assertArrayNotHasKey('grade', $result['submission']);
971         $this->assertArrayNotHasKey('gradeover', $result['submission']);
972         $this->assertArrayHasKey('gradeoverby', $result['submission']);
973         $this->assertArrayNotHasKey('timegraded', $result['submission']);
975         // Switch to a different phase (where feedback won't be available).
976         $workshop->switch_phase(workshop::PHASE_EVALUATION);
977         $result = mod_workshop_external::get_submission($firstsubmissionid);
978         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
979         $this->assertEquals($firstsubmissionid, $result['submission']['id']);
980         $this->assertCount(1, $result['submission']['contentfiles']); // Check we retrieve submission text files.
981         $this->assertCount(1, $result['submission']['attachmentfiles']); // Check we retrieve attachment files.
982         $this->assertArrayNotHasKey('feedbackauthor', $result['submission']);
983         $this->assertArrayNotHasKey('grade', $result['submission']);
984         $this->assertArrayNotHasKey('gradeover', $result['submission']);
985         $this->assertArrayNotHasKey('gradeoverby', $result['submission']);
986         $this->assertArrayNotHasKey('timegraded', $result['submission']);
987     }
989     /**
990      * Test test_get_submission_i_reviewed.
991      */
992     public function test_get_submission_i_reviewed() {
994         // Create a couple of submissions with files.
995         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
996         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
997         $workshopgenerator->create_assessment($firstsubmissionid, $this->anotherstudentg1->id, array(
998             'weight' => 3,
999             'grade' => 95,
1000         ));
1001         // Now try to get the submission I just reviewed.
1002         $this->setUser($this->anotherstudentg1);
1003         $result = mod_workshop_external::get_submission($firstsubmissionid);
1004         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1005         $this->assertEquals($firstsubmissionid, $result['submission']['id']);
1006         $this->assertCount(1, $result['submission']['contentfiles']); // Check we retrieve submission text files.
1007         $this->assertCount(1, $result['submission']['attachmentfiles']); // Check we retrieve attachment files.
1008         $this->assertArrayNotHasKey('feedbackauthor', $result['submission']);
1009         $this->assertArrayNotHasKey('grade', $result['submission']);
1010         $this->assertArrayNotHasKey('gradeover', $result['submission']);
1011         $this->assertArrayNotHasKey('gradeoverby', $result['submission']);
1012         $this->assertArrayNotHasKey('timegraded', $result['submission']);
1013     }
1015     /**
1016      * Test test_get_submission_other_student.
1017      */
1018     public function test_get_submission_other_student() {
1020         // Create a couple of submissions with files.
1021         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
1022         // Expect failure.
1023         $this->setUser($this->anotherstudentg1);
1024         $this->expectException('moodle_exception');
1025         $result = mod_workshop_external::get_submission($firstsubmissionid);
1026     }
1028     /**
1029      * Test test_get_submission_published_student.
1030      */
1031     public function test_get_submission_published_student() {
1033         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1034         $workshop->switch_phase(workshop::PHASE_CLOSED);
1035         // Create a couple of submissions with files.
1036         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1037         $submission = array('published' => 1);
1038         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id, $submission);
1040         $this->setUser($this->student);
1041         $result = mod_workshop_external::get_submission($submissionid);
1042         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1043         $this->assertEquals($submissionid, $result['submission']['id']);
1044         // Check that the student don't see the other student grade/feedback data even if is published.
1045         // We should not see the grade or feedback information.
1046         $properties = submission_exporter::properties_definition();
1047         $this->assertArrayNotHasKey('feedbackauthor', $result['submission']);
1048         $this->assertArrayNotHasKey('grade', $result['submission']);
1049         $this->assertArrayNotHasKey('gradeover', $result['submission']);
1050         $this->assertArrayNotHasKey('gradeoverby', $result['submission']);
1051         $this->assertArrayNotHasKey('timegraded', $result['submission']);
1053         // Check with group restrictions.
1054         $this->setUser($this->anotherstudentg2);
1055         $this->expectException('moodle_exception');
1056         mod_workshop_external::get_submission($submissionid);
1057     }
1059     /**
1060      * Test test_get_submission_from_student_with_feedback_from_teacher.
1061      */
1062     public function test_get_submission_from_student_with_feedback_from_teacher() {
1063         global $DB;
1065         // Create a couple of submissions with files.
1066         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1067         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1068         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1069         $workshop->switch_phase(workshop::PHASE_CLOSED);
1070         // Create teacher feedback for submission.
1071         $record = new stdclass();
1072         $record->id = $submissionid;
1073         $record->gradeover = 9;
1074         $record->gradeoverby = $this->teacher->id;
1075         $record->feedbackauthor = 'Hey';
1076         $record->feedbackauthorformat = FORMAT_MOODLE;
1077         $record->published = 1;
1078         $record->timegraded = time();
1079         $DB->update_record('workshop_submissions', $record);
1081         $this->setUser($this->teacher);
1082         $result = mod_workshop_external::get_submission($submissionid);
1083         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1084         $this->assertEquals($submissionid, $result['submission']['id']);
1085         $this->assertEquals($record->feedbackauthor, $result['submission']['feedbackauthor']);
1086         $this->assertEquals($record->gradeover, $result['submission']['gradeover']);
1087         $this->assertEquals($record->gradeoverby, $result['submission']['gradeoverby']);
1088         $this->assertEquals($record->timegraded, $result['submission']['timegraded']);
1090         // Go to phase where feedback and grades are not yet available.
1091         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
1092         $result = mod_workshop_external::get_submission($submissionid);
1093         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1094         $this->assertArrayNotHasKey('feedbackauthor', $result['submission']);
1095         $this->assertArrayNotHasKey('grade', $result['submission']);
1096         $this->assertArrayNotHasKey('gradeover', $result['submission']);
1097         $this->assertArrayNotHasKey('gradeoverby', $result['submission']);
1098         $this->assertArrayNotHasKey('timegraded', $result['submission']);
1100         // Remove teacher caps to view and go to valid phase.
1101         $workshop->switch_phase(workshop::PHASE_EVALUATION);
1102         unassign_capability('mod/workshop:viewallsubmissions', $this->teacherrole->id);
1103         // Empty all the caches that may be affected  by this change.
1104         accesslib_clear_all_caches_for_unit_testing();
1106         $this->expectException('moodle_exception');
1107         mod_workshop_external::get_submission($submissionid);
1108     }
1110     /**
1111      * Test test_get_submission_from_students_as_teacher.
1112      */
1113     public function test_get_submission_from_students_as_teacher() {
1114         // Create a couple of submissions with files.
1115         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1116         $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1117         $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
1118         $submissionid3 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg2->id);
1120         $this->setUser($this->teacher);
1121         $result = mod_workshop_external::get_submission($submissionid1); // Get all.
1122         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1123         $this->assertEquals($submissionid1, $result['submission']['id']);
1125         $result = mod_workshop_external::get_submission($submissionid3); // Get group 2.
1126         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1127         $this->assertEquals($submissionid3, $result['submission']['id']);
1128     }
1131     /**
1132      * Test get_submission_assessments_student.
1133      */
1134     public function test_get_submission_assessments_student() {
1136         // Create the submission that will be deleted.
1137         $submissionid = $this->create_test_submission($this->student);
1139         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1140         $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1141             'weight' => 3,
1142             'grade' => 95,
1143         ));
1144         $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1145             'weight' => 2,
1146             'grade' => 90,
1147         ));
1149         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1150         $workshop->switch_phase(workshop::PHASE_CLOSED);
1151         $this->setUser($this->student);
1152         $result = mod_workshop_external::get_submission_assessments($submissionid);
1153         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_assessments_returns(), $result);
1154         $this->assertCount(2, $result['assessments']);  // I received my two assessments.
1155         foreach ($result['assessments'] as $assessment) {
1156             if ($assessment['grade'] == 90) {
1157                 // My own assessment, I can see me.
1158                 $this->assertEquals($this->student->id, $assessment['reviewerid']);
1159             } else {
1160                 // Student's can't see who did the review.
1161                 $this->assertEquals(0, $assessment['reviewerid']);
1162             }
1163         }
1164     }
1166     /**
1167      * Test get_submission_assessments_invalid_phase.
1168      */
1169     public function test_get_submission_assessments_invalid_phase() {
1171         // Create the submission that will be deleted.
1172         $submissionid = $this->create_test_submission($this->student);
1174         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1175         $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1176             'weight' => 3,
1177             'grade' => 95,
1178         ));
1180         $this->expectException('moodle_exception');
1181         mod_workshop_external::get_submission_assessments($submissionid);
1182     }
1184     /**
1185      * Test get_submission_assessments_teacher.
1186      */
1187     public function test_get_submission_assessments_teacher() {
1189         // Create the submission that will be deleted.
1190         $submissionid = $this->create_test_submission($this->student);
1192         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1193         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1194             'weight' => 1,
1195             'grade' => 50,
1196         ));
1198         $this->setUser($this->teacher);
1199         $result = mod_workshop_external::get_submission_assessments($submissionid);
1200         $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_assessments_returns(), $result);
1201         $this->assertCount(1, $result['assessments']);
1202         $this->assertEquals(50, $result['assessments'][0]['grade']);
1203         $this->assertEquals($assessmentid, $result['assessments'][0]['id']);
1204     }
1206     /**
1207      * Test get_assessment_author.
1208      */
1209     public function test_get_assessment_author() {
1211         // Create the submission.
1212         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1214         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1215         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1216             'weight' => 2,
1217             'grade' => 90,
1218         ));
1220         // Switch to closed phase.
1221         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1222         $workshop->switch_phase(workshop::PHASE_CLOSED);
1223         $this->setUser($this->anotherstudentg1);
1224         $result = mod_workshop_external::get_assessment($assessmentid);
1225         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1226         $this->assertEquals($assessmentid, $result['assessment']['id']);
1227         $this->assertEquals(90, $result['assessment']['grade']);
1228         // I can't see the reviewer review.
1229         $this->assertFalse(isset($result['assessment']['feedbackreviewer']));
1230     }
1232     /**
1233      * Test get_assessment_reviewer.
1234      */
1235     public function test_get_assessment_reviewer() {
1237         // Create the submission.
1238         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1240         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1241         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1242             'weight' => 2,
1243             'grade' => 90,
1244         ));
1246         // Switch to closed phase.
1247         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1248         $workshop->switch_phase(workshop::PHASE_CLOSED);
1249         $this->setUser($this->student);
1250         $result = mod_workshop_external::get_assessment($assessmentid);
1251         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1252         $this->assertEquals($assessmentid, $result['assessment']['id']);
1253         $this->assertEquals(90, $result['assessment']['grade']);
1254         // I can see the reviewer review.
1255         $this->assertTrue(isset($result['assessment']['feedbackreviewer']));
1256     }
1258     /**
1259      * Test get_assessment_teacher.
1260      */
1261     public function test_get_assessment_teacher() {
1263         // Create the submission.
1264         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1266         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1267         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1268             'weight' => 2,
1269             'grade' => 90,
1270         ));
1272         // Switch to closed phase.
1273         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1274         $workshop->switch_phase(workshop::PHASE_CLOSED);
1275         $this->setUser($this->teacher);
1276         $result = mod_workshop_external::get_assessment($assessmentid);
1277         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1278         $this->assertEquals($assessmentid, $result['assessment']['id']);
1279         $this->assertEquals(90, $result['assessment']['grade']);
1280     }
1282     /**
1283      * Test get_assessment_student_invalid_phase.
1284      */
1285     public function test_get_assessment_student_invalid_phase() {
1287         // Create the submission.
1288         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1290         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1291         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1292             'weight' => 2,
1293             'grade' => 90,
1294         ));
1296         // Switch to closed phase.
1297         $this->setUser($this->anotherstudentg1);
1299         $this->expectException('moodle_exception');
1300         mod_workshop_external::get_assessment($assessmentid);
1301     }
1303     /**
1304      * Test get_assessment_student_invalid_user.
1305      */
1306     public function test_get_assessment_student_invalid_user() {
1308         // Create the submission.
1309         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1311         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1312         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1313             'weight' => 2,
1314             'grade' => 90,
1315         ));
1317         // Switch to closed phase.
1318         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1319         $workshop->switch_phase(workshop::PHASE_CLOSED);
1320         $this->setUser($this->anotherstudentg2);
1322         $this->expectException('moodle_exception');
1323         mod_workshop_external::get_assessment($assessmentid);
1324     }
1326     /**
1327      * Test get_assessment_form_definition_reviewer_new_assessment.
1328      */
1329     public function test_get_assessment_form_definition_reviewer_new_assessment() {
1331         // Create the submission.
1332         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1334         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1335         $submission = $workshop->get_submission_by_id($submissionid);
1336         $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1338         // Switch to assessment phase.
1339         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1340         $this->setUser($this->student);
1341         $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1342         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1343         $this->assertEquals(4, $result['dimenssionscount']);    // We receive the expected 4 dimensions.
1344         $this->assertEmpty($result['current']); // Assessment not yet done.
1345         foreach ($result['fields'] as $field) {
1346             if (strpos($field['name'], 'grade__idx_') === 0) {
1347                 $this->assertEquals(25, $field['value']); // Check one of the dimension fields attributes.
1348             }
1349         }
1350         // Check dimensions grading info.
1351         foreach ($result['dimensionsinfo'] as $dimension) {
1352             $this->assertEquals(0, $dimension['min']);
1353             $this->assertEquals(25, $dimension['max']);
1354             $this->assertEquals(25, $dimension['weight']);
1355             $this->assertFalse(isset($dimension['scale']));
1356         }
1357     }
1359     /**
1360      * Test get_assessment_form_definition_teacher_new_assessment.
1361      */
1362     public function test_get_assessment_form_definition_teacher_new_assessment() {
1364         // Create the submission.
1365         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1367         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1368         $submission = $workshop->get_submission_by_id($submissionid);
1369         $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1371         // Switch to assessment phase.
1372         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1373         // Teachers need to be able to view assessments.
1374         $this->setUser($this->teacher);
1375         $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1376         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1377         $this->assertEquals(4, $result['dimenssionscount']);
1378     }
1380     /**
1381      * Test get_assessment_form_definition_invalid_phase.
1382      */
1383     public function test_get_assessment_form_definition_invalid_phase() {
1385         // Create the submission.
1386         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1388         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1389         $submission = $workshop->get_submission_by_id($submissionid);
1390         $assessmentid = $workshop->add_allocation($submission, $this->anotherstudentg1->id);
1392         $workshop->switch_phase(workshop::PHASE_EVALUATION);
1393         $this->setUser($this->student);
1394         // Since we are not reviewers we can't see the assessment until the workshop is closed.
1395         $this->expectException('moodle_exception');
1396         mod_workshop_external::get_assessment_form_definition($assessmentid);
1397     }
1399     /**
1400      * Test get_reviewer_assessments.
1401      */
1402     public function test_get_reviewer_assessments() {
1404         // Create the submission.
1405         $submissionid1 = $this->create_test_submission($this->student);
1406         $submissionid2 = $this->create_test_submission($this->anotherstudentg1);
1408         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1409         $assessmentid1 = $workshopgenerator->create_assessment($submissionid1, $this->student->id, array(
1410             'weight' => 2,
1411             'grade' => 90,
1412         ));
1413         $assessmentid2 = $workshopgenerator->create_assessment($submissionid2, $this->student->id, array(
1414             'weight' => 3,
1415             'grade' => 80,
1416         ));
1418         // Switch to assessment phase.
1419         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1420         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1421         $this->setUser($this->student);
1422         // Get my assessments.
1423         $result = mod_workshop_external::get_reviewer_assessments($this->workshop->id);
1424         $result = external_api::clean_returnvalue(mod_workshop_external::get_reviewer_assessments_returns(), $result);
1425         $this->assertCount(2, $result['assessments']);
1426         foreach ($result['assessments'] as $assessment) {
1427             if ($assessment['id'] == $assessmentid1) {
1428                 $this->assertEquals(90, $assessment['grade']);
1429             } else {
1430                 $this->assertEquals($assessmentid2, $assessment['id']);
1431                 $this->assertEquals(80, $assessment['grade']);
1432             }
1433         }
1435         // Now, as teacher try to get the same student assessments.
1436         $result = mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->student->id);
1437         $result = external_api::clean_returnvalue(mod_workshop_external::get_reviewer_assessments_returns(), $result);
1438         $this->assertCount(2, $result['assessments']);
1439     }
1441     /**
1442      * Test get_reviewer_assessments_other_student.
1443      */
1444     public function test_get_reviewer_assessments_other_student() {
1446         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1447         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1448         // Try to get other user assessments.
1449         $this->setUser($this->student);
1450         $this->expectException('moodle_exception');
1451         mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->anotherstudentg1->id);
1452     }
1454     /**
1455      * Test get_reviewer_assessments_invalid_phase.
1456      */
1457     public function test_get_reviewer_assessments_invalid_phase() {
1459         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1460         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
1461         // Try to get other user assessments.
1462         $this->setUser($this->student);
1463         $this->expectException('moodle_exception');
1464         mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->anotherstudentg1->id);
1465     }
1467     /**
1468      * Test update_assessment.
1469      */
1470     public function test_update_assessment() {
1472         // Create the submission.
1473         $submissionid = $this->create_test_submission($this->anotherstudentg1);
1475         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1476         $submission = $workshop->get_submission_by_id($submissionid);
1477         $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1479         // Switch to assessment phase.
1480         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1481         $this->setUser($this->student);
1482         // Get the form definition.
1483         $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1484         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1486         // Prepare the data to be sent.
1487         $data = $result['fields'];
1488         foreach ($data as $key => $param) {
1489             if (strpos($param['name'], 'peercomment__idx_') === 0) {
1490                 $data[$key]['value'] = 'Some content';
1491             } else if (strpos($param['name'], 'grade__idx_') === 0) {
1492                 $data[$key]['value'] = 25; // Set all to 25.
1493             }
1494         }
1496         // Required data.
1497         $data[] = array(
1498             'name' => 'nodims',
1499             'value' => $result['dimenssionscount'],
1500         );
1502         // General feedback.
1503         $data[] = array(
1504             'name' => 'feedbackauthor',
1505             'value' => 'Feedback for the author',
1506         );
1507         $data[] = array(
1508             'name' => 'feedbackauthorformat',
1509             'value' => FORMAT_MOODLE,
1510         );
1512         // Create a file in a draft area for inline attachments.
1513         $fs = get_file_storage();
1514         $draftidinlineattach = file_get_unused_draft_itemid();
1515         $usercontext = context_user::instance($this->student->id);
1516         $filenameimg = 'shouldbeanimage.txt';
1517         $filerecordinline = array(
1518             'contextid' => $usercontext->id,
1519             'component' => 'user',
1520             'filearea'  => 'draft',
1521             'itemid'    => $draftidinlineattach,
1522             'filepath'  => '/',
1523             'filename'  => $filenameimg,
1524         );
1525         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
1527         // Create a file in a draft area for regular attachments.
1528         $draftidattach = file_get_unused_draft_itemid();
1529         $filerecordattach = $filerecordinline;
1530         $attachfilename = 'attachment.txt';
1531         $filerecordattach['filename'] = $attachfilename;
1532         $filerecordattach['itemid'] = $draftidattach;
1533         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
1535         $data[] = array(
1536             'name' => 'feedbackauthorinlineattachmentsid',
1537             'value' => $draftidinlineattach,
1538         );
1539         $data[] = array(
1540             'name' => 'feedbackauthorattachmentsid',
1541             'value' => $draftidattach,
1542         );
1544         // Update the assessment.
1545         $result = mod_workshop_external::update_assessment($assessmentid, $data);
1546         $result = external_api::clean_returnvalue(mod_workshop_external::update_assessment_returns(), $result);
1547         $this->assertEquals(100, $result['rawgrade']);
1548         $this->assertTrue($result['status']);
1550         // Get the assessment and check it was updated properly.
1551         $result = mod_workshop_external::get_assessment($assessmentid);
1552         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1553         $this->assertEquals(100, $result['assessment']['grade']);
1554         $this->assertEquals($this->student->id, $result['assessment']['reviewerid']);
1555         $this->assertEquals('Feedback for the author', $result['assessment']['feedbackauthor']);
1556         $this->assertCount(1, $result['assessment']['feedbackcontentfiles']);
1557         $this->assertCount(1, $result['assessment']['feedbackattachmentfiles']);
1559         // Now, get again the form and check we received the data we already sent.
1560         $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1561         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1562         foreach ($result['current'] as $currentdata) {
1563             if (strpos($currentdata['name'], 'peercomment__idx_') === 0) {
1564                 $this->assertEquals('Some content', $currentdata['value']);
1565             } else if (strpos($currentdata['name'], 'grade__idx_') === 0) {
1566                 $this->assertEquals(25, (int) $currentdata['value']);
1567             }
1568         }
1569     }
1571     /**
1572      * Test get_grades.
1573      */
1574     public function test_get_grades() {
1576         $timenow = time();
1577         $submissiongrade = array(
1578             'userid' => $this->student->id,
1579             'rawgrade' => 40,
1580             'feedback' => '',
1581             'feedbackformat' => 1,
1582             'datesubmitted' => $timenow,
1583             'dategraded' => $timenow,
1584         );
1585         $assessmentgrade = array(
1586             'userid' => $this->student->id,
1587             'rawgrade' => 10,
1588             'feedback' => '',
1589             'feedbackformat' => 1,
1590             'datesubmitted' => $timenow,
1591             'dategraded' => $timenow,
1592         );
1594         workshop_grade_item_update($this->workshop, (object) $submissiongrade, (object) $assessmentgrade);
1596         // First retrieve my grades.
1597         $this->setUser($this->student);
1598         $result = mod_workshop_external::get_grades($this->workshop->id);
1599         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_returns(), $result);
1600         $this->assertCount(0, $result['warnings']);
1601         $this->assertEquals($assessmentgrade['rawgrade'], $result['assessmentrawgrade']);
1602         $this->assertEquals($submissiongrade['rawgrade'], $result['submissionrawgrade']);
1603         $this->assertFalse($result['assessmentgradehidden']);
1604         $this->assertFalse($result['submissiongradehidden']);
1605         $this->assertEquals($assessmentgrade['rawgrade'] . ".00 / 20.00", $result['assessmentlongstrgrade']);
1606         $this->assertEquals($submissiongrade['rawgrade'] . ".00 / 80.00", $result['submissionlongstrgrade']);
1608         // Second, teacher retrieve user grades.
1609         $this->setUser($this->teacher);
1610         $result = mod_workshop_external::get_grades($this->workshop->id, $this->student->id);
1611         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_returns(), $result);
1612         $this->assertCount(0, $result['warnings']);
1613         $this->assertEquals($assessmentgrade['rawgrade'], $result['assessmentrawgrade']);
1614         $this->assertEquals($submissiongrade['rawgrade'], $result['submissionrawgrade']);
1615         $this->assertFalse($result['assessmentgradehidden']);
1616         $this->assertFalse($result['submissiongradehidden']);
1617         $this->assertEquals($assessmentgrade['rawgrade'] . ".00 / 20.00", $result['assessmentlongstrgrade']);
1618         $this->assertEquals($submissiongrade['rawgrade'] . ".00 / 80.00", $result['submissionlongstrgrade']);
1619     }
1621     /**
1622      * Test get_grades_other_student.
1623      */
1624     public function test_get_grades_other_student() {
1626         // Create the submission that will be deleted.
1627         $submissionid = $this->create_test_submission($this->student);
1629         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1630         $workshop->switch_phase(workshop::PHASE_CLOSED);
1631         $this->setUser($this->anotherstudentg1);
1632         $this->expectException('moodle_exception');
1633         mod_workshop_external::get_grades($this->workshop->id, $this->student->id);
1634     }
1636     /**
1637      * Test evaluate_assessment.
1638      */
1639     public function test_evaluate_assessment() {
1640         global $DB;
1642         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1643         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1644         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1645             'weight' => 3,
1646             'grade' => 20,
1647         ));
1649         $this->setUser($this->teacher);
1650         $feedbacktext = 'The feedback';
1651         $feedbackformat = FORMAT_MOODLE;
1652         $weight = 10;
1653         $gradinggradeover = 10;
1654         $result = mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight,
1655             $gradinggradeover);
1656         $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_assessment_returns(), $result);
1657         $this->assertTrue($result['status']);
1659         $assessment = $DB->get_record('workshop_assessments', array('id' => $assessmentid));
1660         $this->assertEquals('The feedback', $assessment->feedbackreviewer);
1661         $this->assertEquals(10, $assessment->weight);
1663         // Now test passing incorrect weight and grade values.
1664         $weight = 17;
1665         $gradinggradeover = 100;
1666         $result = mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight,
1667             $gradinggradeover);
1668         $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_assessment_returns(), $result);
1669         $this->assertFalse($result['status']);
1670         $this->assertCount(2, $result['warnings']);
1671         $found = 0;
1672         foreach ($result['warnings'] as $warning) {
1673             if ($warning['item'] == 'weight' || $warning['item'] == 'gradinggradeover') {
1674                 $found++;
1675             }
1676         }
1677         $this->assertEquals(2, $found);
1678     }
1680     /**
1681      * Test evaluate_assessment_ignore_parameters.
1682      */
1683     public function test_evaluate_assessment_ignore_parameters() {
1684         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1685         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1686         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1687             'weight' => 3,
1688             'grade' => 20,
1689         ));
1691         assign_capability('mod/workshop:allocate', CAP_PROHIBIT, $this->teacherrole->id, $this->context->id);
1692         // Empty all the caches that may be affected  by this change.
1693         accesslib_clear_all_caches_for_unit_testing();
1695         $this->setUser($this->teacher);
1696         $feedbacktext = 'The feedback';
1697         $feedbackformat = FORMAT_MOODLE;
1698         $weight = 10;
1699         $gradinggradeover = 19;
1700         $result = mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight,
1701             $gradinggradeover);
1702         $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_assessment_returns(), $result);
1703         $this->assertTrue($result['status']);
1705         $result = mod_workshop_external::get_assessment($assessmentid);
1706         $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1707         $this->assertNotEquals(10, $result['assessment']['weight']);
1708     }
1710     /**
1711      * Test evaluate_assessment_no_permissions.
1712      */
1713     public function test_evaluate_assessment_no_permissions() {
1714         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1715         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1716         $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1717             'weight' => 3,
1718             'grade' => 20,
1719         ));
1721         $this->setUser($this->student);
1722         $feedbacktext = 'The feedback';
1723         $feedbackformat = FORMAT_MOODLE;
1724         $weight = 10;
1725         $gradinggradeover = 50;
1726         $this->expectException('moodle_exception');
1727         mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight, $gradinggradeover);
1728     }
1730     /**
1731      * Test get_grades_report.
1732      */
1733     public function test_get_grades_report() {
1735         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1736         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1737         $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1738         $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
1740         $assessmentid1 = $workshopgenerator->create_assessment($submissionid2, $this->student->id, array(
1741             'weight' => 100,
1742             'grade' => 50,
1743         ));
1744         $assessmentid2 = $workshopgenerator->create_assessment($submissionid1, $this->anotherstudentg1->id, array(
1745             'weight' => 100,
1746             'grade' => 55,
1747         ));
1749         $workshop->switch_phase(workshop::PHASE_CLOSED);
1750         $this->setUser($this->teacher);
1751         $result = mod_workshop_external::get_grades_report($this->workshop->id);
1752         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1753         $this->assertEquals(3, $result['report']['totalcount']); // Expect 3 potential submissions.
1755         foreach ($result['report']['grades'] as $grade) {
1756             if ($grade['userid'] == $this->student->id) {
1757                 $this->assertEquals($this->anotherstudentg1->id, $grade['reviewedby'][0]['userid']); // Check reviewer.
1758                 $this->assertEquals($this->anotherstudentg1->id, $grade['reviewerof'][0]['userid']); // Check reviewer.
1759                 $this->assertEquals($workshop->real_grade(50), $grade['reviewerof'][0]['grade']); // Check grade (converted).
1760                 $this->assertEquals($workshop->real_grade(55), $grade['reviewedby'][0]['grade']); // Check grade (converted).
1761             } else if ($grade['userid'] == $this->anotherstudentg1->id) {
1762                 $this->assertEquals($this->student->id, $grade['reviewedby'][0]['userid']); // Check reviewer.
1763                 $this->assertEquals($this->student->id, $grade['reviewerof'][0]['userid']); // Check reviewer.
1764                 $this->assertEquals($workshop->real_grade(55), $grade['reviewerof'][0]['grade']); // Check grade (converted).
1765                 $this->assertEquals($workshop->real_grade(50), $grade['reviewedby'][0]['grade']); // Check grade (converted).
1766             }
1767         }
1768         // Now check pagination.
1769         $result = mod_workshop_external::get_grades_report($this->workshop->id, 0, 'lastname', 'ASC', 0, 1);
1770         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1771         $this->assertEquals(3, $result['report']['totalcount']); // Expect the total count.
1772         $this->assertCount(1, $result['report']['grades']);
1774         // Groups filtering.
1775         $result = mod_workshop_external::get_grades_report($this->workshop->id, $this->group1->id);
1776         $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1777         $this->assertEquals(2, $result['report']['totalcount']); // Expect the group count.
1778     }
1780     /**
1781      * Test get_grades_report_invalid_phase.
1782      */
1783     public function test_get_grades_report_invalid_phase() {
1784         $this->setUser($this->teacher);
1785         $this->expectException('moodle_exception');
1786         $this->expectExceptionMessage(get_string('nothingfound', 'workshop'));
1787         mod_workshop_external::get_grades_report($this->workshop->id);
1788     }
1790     /**
1791      * Test get_grades_report_missing_permissions.
1792      */
1793     public function test_get_grades_report_missing_permissions() {
1794         $this->setUser($this->student);
1795         $this->expectException('required_capability_exception');
1796         mod_workshop_external::get_grades_report($this->workshop->id);
1797     }
1799     /**
1800      * Test test_view_submission.
1801      */
1802     public function test_view_submission() {
1804         // Create a couple of submissions with files.
1805         $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
1807         // Trigger and capture the event.
1808         $sink = $this->redirectEvents();
1810         $this->setUser($this->student);
1811         $result = mod_workshop_external::view_submission($firstsubmissionid);
1812         $result = external_api::clean_returnvalue(mod_workshop_external::view_submission_returns(), $result);
1814         $events = $sink->get_events();
1815         $this->assertCount(1, $events);
1816         $event = array_shift($events);
1818         // Checking that the event contains the expected values.
1819         $this->assertInstanceOf('\mod_workshop\event\submission_viewed', $event);
1820         $this->assertEquals($this->context, $event->get_context());
1821         $moodleworkshop = new \moodle_url('/mod/workshop/submission.php', array('id' => $firstsubmissionid,
1822             'cmid' => $this->cm->id));
1823         $this->assertEquals($moodleworkshop, $event->get_url());
1824         $this->assertEventContextNotUsed($event);
1825         $this->assertNotEmpty($event->get_name());
1827     }
1829     /**
1830      * Test evaluate_submission.
1831      */
1832     public function test_evaluate_submission() {
1833         global $DB;
1835         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1836         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1838         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1839         $workshop->switch_phase(workshop::PHASE_EVALUATION);
1841         $this->setUser($this->teacher);
1842         $feedbacktext = 'The feedback';
1843         $feedbackformat = FORMAT_MOODLE;
1844         $published = 1;
1845         $gradeover = 10;
1846         $result = mod_workshop_external::evaluate_submission($submissionid, $feedbacktext, $feedbackformat, $published,
1847             $gradeover);
1848         $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_submission_returns(), $result);
1849         $this->assertTrue($result['status']);
1851         $submission = $DB->get_record('workshop_submissions', array('id' => $submissionid));
1852         $this->assertEquals($feedbacktext, $submission->feedbackauthor);
1853         $this->assertEquals($workshop->raw_grade_value($gradeover, $workshop->grade), $submission->gradeover);  // Expected grade.
1854         $this->assertEquals(1, $submission->published); // Submission published.
1855     }
1857     /**
1858      * Test evaluate_submission_invalid_phase_for_override.
1859      */
1860     public function test_evaluate_submission_invalid_phase_for_override() {
1861         global $DB;
1863         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1864         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1866         $this->setUser($this->teacher);
1867         $feedbacktext = 'The feedback';
1868         $feedbackformat = FORMAT_MOODLE;
1869         $published = 1;
1870         $gradeover = 10;
1871         $result = mod_workshop_external::evaluate_submission($submissionid, $feedbacktext, $feedbackformat, $published,
1872             $gradeover);
1873         $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_submission_returns(), $result);
1874         $this->assertTrue($result['status']);
1876         $submission = $DB->get_record('workshop_submissions', array('id' => $submissionid));
1877         $this->assertEquals('', $submission->feedbackauthor);   // Feedback and grade not updated.
1878         $this->assertEquals(0, $submission->gradeover);
1879         $this->assertEquals(1, $submission->published); // Publishing status correctly updated.
1880     }
1882     /**
1883      * Test evaluate_submission_no_permissions.
1884      */
1885     public function test_evaluate_submission_no_permissions() {
1887         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1888         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1889         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1890         $workshop->switch_phase(workshop::PHASE_EVALUATION);
1892         $this->setUser($this->student);
1893         $feedbacktext = 'The feedback';
1894         $feedbackformat = FORMAT_MOODLE;
1895         $published = 1;
1896         $gradeover = 50;
1897         $this->expectException('moodle_exception');
1898         mod_workshop_external::evaluate_submission($submissionid, $feedbacktext, $feedbackformat, $published, $gradeover);
1899     }
1901     /**
1902      * Test evaluate_submission_invalid_grade.
1903      */
1904     public function test_evaluate_submission_invalid_grade() {
1906         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1907         $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1908         $workshop = new workshop($this->workshop, $this->cm, $this->course);
1909         $workshop->switch_phase(workshop::PHASE_EVALUATION);
1911         $this->setUser($this->teacher);
1912         $feedbacktext = 'The feedback';
1913         $feedbackformat = FORMAT_MOODLE;
1914         $published = 1;
1915         $gradeover = 150;
1916         $result = mod_workshop_external::evaluate_submission($submissionid, $feedbacktext, $feedbackformat, $published, $gradeover);
1917         $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_submission_returns(), $result);
1918         $this->assertCount(1, $result['warnings']);
1919         $this->assertFalse($result['status']);
1920         $this->assertEquals('gradeover', $result['warnings'][0]['item']);
1921     }