MDL-59244 mod_workshop: New WS mod_workshop_delete_submission
[moodle.git] / mod / workshop / tests / external_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Workshop module external functions tests
19  *
20  * @package    mod_workshop
21  * @category   external
22  * @copyright  2017 Juan Leyva <juan@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  * @since      Moodle 3.4
25  */
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
31 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32 require_once($CFG->dirroot . '/mod/workshop/lib.php');
34 use mod_workshop\external\workshop_summary_exporter;
36 /**
37  * Workshop module external functions tests
38  *
39  * @package    mod_workshop
40  * @category   external
41  * @copyright  2017 Juan Leyva <juan@moodle.com>
42  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43  * @since      Moodle 3.4
44  */
45 class mod_workshop_external_testcase extends externallib_advanced_testcase {
47     /** @var stdClass course object */
48     private $course;
49     /** @var stdClass workshop object */
50     private $workshop;
51     /** @var stdClass context object */
52     private $context;
53     /** @var stdClass cm object */
54     private $cm;
55     /** @var stdClass student object */
56     private $student;
57     /** @var stdClass teacher object */
58     private $teacher;
59     /** @var stdClass student role object */
60     private $studentrole;
61     /** @var stdClass teacher role object */
62     private $teacherrole;
64     /**
65      * Set up for every test
66      */
67     public function setUp() {
68         global $DB;
69         $this->resetAfterTest();
70         $this->setAdminUser();
72         // Setup test data.
73         $this->course = $this->getDataGenerator()->create_course();
74         $this->workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $this->course->id));
75         $this->context = context_module::instance($this->workshop->cmid);
76         $this->cm = get_coursemodule_from_instance('workshop', $this->workshop->id);
78         // Create users.
79         $this->student = self::getDataGenerator()->create_user();
80         $this->teacher = self::getDataGenerator()->create_user();
82         // Users enrolments.
83         $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
84         $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
85         $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual');
86         $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
87     }
89     /**
90      * Test test_mod_workshop_get_workshops_by_courses
91      */
92     public function test_mod_workshop_get_workshops_by_courses() {
93         global $DB;
95         // Create additional course.
96         $course2 = self::getDataGenerator()->create_course();
98         // Second workshop.
99         $record = new stdClass();
100         $record->course = $course2->id;
101         $workshop2 = self::getDataGenerator()->create_module('workshop', $record);
103         // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
104         $enrol = enrol_get_plugin('manual');
105         $enrolinstances = enrol_get_instances($course2->id, true);
106         foreach ($enrolinstances as $courseenrolinstance) {
107             if ($courseenrolinstance->enrol == "manual") {
108                 $instance2 = $courseenrolinstance;
109                 break;
110             }
111         }
112         $enrol->enrol_user($instance2, $this->student->id, $this->studentrole->id);
114         self::setUser($this->student);
116         $returndescription = mod_workshop_external::get_workshops_by_courses_returns();
118         // Create what we expect to be returned when querying the two courses.
119         $properties = workshop_summary_exporter::read_properties_definition();
120         $expectedfields = array_keys($properties);
122         // Add expected coursemodule and data.
123         $workshop1 = $this->workshop;
124         $workshop1->coursemodule = $workshop1->cmid;
125         $workshop1->introformat = 1;
126         $workshop1->introfiles = [];
127         $workshop1->instructauthorsfiles = [];
128         $workshop1->instructauthorsformat = 1;
129         $workshop1->instructreviewersfiles = [];
130         $workshop1->instructreviewersformat = 1;
131         $workshop1->conclusionfiles = [];
132         $workshop1->conclusionformat = 1;
134         $workshop2->coursemodule = $workshop2->cmid;
135         $workshop2->introformat = 1;
136         $workshop2->introfiles = [];
137         $workshop2->instructauthorsfiles = [];
138         $workshop2->instructauthorsformat = 1;
139         $workshop2->instructreviewersfiles = [];
140         $workshop2->instructreviewersformat = 1;
141         $workshop2->conclusionfiles = [];
142         $workshop2->conclusionformat = 1;
144         foreach ($expectedfields as $field) {
145             if (!empty($properties[$field]) && $properties[$field]['type'] == PARAM_BOOL) {
146                 $workshop1->{$field} = (bool) $workshop1->{$field};
147                 $workshop2->{$field} = (bool) $workshop2->{$field};
148             }
149             $expected1[$field] = $workshop1->{$field};
150             $expected2[$field] = $workshop2->{$field};
151         }
153         $expectedworkshops = array($expected2, $expected1);
155         // Call the external function passing course ids.
156         $result = mod_workshop_external::get_workshops_by_courses(array($course2->id, $this->course->id));
157         $result = external_api::clean_returnvalue($returndescription, $result);
159         $this->assertEquals($expectedworkshops, $result['workshops']);
160         $this->assertCount(0, $result['warnings']);
162         // Call the external function without passing course id.
163         $result = mod_workshop_external::get_workshops_by_courses();
164         $result = external_api::clean_returnvalue($returndescription, $result);
165         $this->assertEquals($expectedworkshops, $result['workshops']);
166         $this->assertCount(0, $result['warnings']);
168         // Unenrol user from second course and alter expected workshops.
169         $enrol->unenrol_user($instance2, $this->student->id);
170         array_shift($expectedworkshops);
172         // Call the external function without passing course id.
173         $result = mod_workshop_external::get_workshops_by_courses();
174         $result = external_api::clean_returnvalue($returndescription, $result);
175         $this->assertEquals($expectedworkshops, $result['workshops']);
177         // Call for the second course we unenrolled the user from, expected warning.
178         $result = mod_workshop_external::get_workshops_by_courses(array($course2->id));
179         $this->assertCount(1, $result['warnings']);
180         $this->assertEquals('1', $result['warnings'][0]['warningcode']);
181         $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
182     }
184     /**
185      * Test mod_workshop_get_workshop_access_information for students.
186      */
187     public function test_mod_workshop_get_workshop_access_information_student() {
189         self::setUser($this->student);
190         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
191         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
192         // Check default values for capabilities.
193         $enabledcaps = array('canpeerassess', 'cansubmit', 'canview', 'canviewauthornames', 'canviewauthorpublished',
194             'canviewpublishedsubmissions', 'canexportsubmissions');
196         foreach ($result as $capname => $capvalue) {
197             if (strpos($capname, 'can') !== 0) {
198                 continue;
199             }
200             if (in_array($capname, $enabledcaps)) {
201                 $this->assertTrue($capvalue);
202             } else {
203                 $this->assertFalse($capvalue);
204             }
205         }
206         // Now, unassign some capabilities.
207         unassign_capability('mod/workshop:peerassess', $this->studentrole->id);
208         unassign_capability('mod/workshop:submit', $this->studentrole->id);
209         unset($enabledcaps[0]);
210         unset($enabledcaps[1]);
211         accesslib_clear_all_caches_for_unit_testing();
213         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
214         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
215         foreach ($result as $capname => $capvalue) {
216             if (strpos($capname, 'can') !== 0) {
217                 continue;
218             }
219             if (in_array($capname, $enabledcaps)) {
220                 $this->assertTrue($capvalue);
221             } else {
222                 $this->assertFalse($capvalue);
223             }
224         }
226         // Now, specific functionalities.
227         $this->assertFalse($result['creatingsubmissionallowed']);
228         $this->assertFalse($result['modifyingsubmissionallowed']);
229         $this->assertFalse($result['assessingallowed']);
230         $this->assertFalse($result['assessingexamplesallowed']);
231         $this->assertTrue($result['examplesassessed']);
233         // Switch phase.
234         $workshop = new workshop($this->workshop, $this->cm, $this->course);
235         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
236         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
237         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
239         $this->assertTrue($result['creatingsubmissionallowed']);
240         $this->assertTrue($result['modifyingsubmissionallowed']);
241         $this->assertFalse($result['assessingallowed']);
242         $this->assertFalse($result['assessingexamplesallowed']);
243         $this->assertTrue($result['examplesassessed']);
245         // Switch to next (to assessment).
246         $workshop = new workshop($this->workshop, $this->cm, $this->course);
247         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
248         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
249         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
251         $this->assertFalse($result['creatingsubmissionallowed']);
252         $this->assertFalse($result['modifyingsubmissionallowed']);
253         $this->assertTrue($result['assessingallowed']);
254         $this->assertFalse($result['assessingexamplesallowed']);
255         $this->assertTrue($result['examplesassessed']);
256     }
258     /**
259      * Test mod_workshop_get_workshop_access_information for teachers.
260      */
261     public function test_mod_workshop_get_workshop_access_information_teacher() {
263         self::setUser($this->teacher);
264         $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
265         $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
266         // Check default values.
267         $disabledcaps = array('canpeerassess', 'cansubmit');
269         foreach ($result as $capname => $capvalue) {
270             if (strpos($capname, 'can') !== 0) {
271                 continue;
272             }
273             if (in_array($capname, $disabledcaps)) {
274                 $this->assertFalse($capvalue);
275             } else {
276                 $this->assertTrue($capvalue);
277             }
278         }
280         // Now, specific functionalities.
281         $this->assertFalse($result['creatingsubmissionallowed']);
282         $this->assertFalse($result['modifyingsubmissionallowed']);
283         $this->assertFalse($result['assessingallowed']);
284         $this->assertFalse($result['assessingexamplesallowed']);
285     }
287     /**
288      * Test mod_workshop_get_user_plan for students.
289      */
290     public function test_mod_workshop_get_user_plan_student() {
292         self::setUser($this->student);
293         $result = mod_workshop_external::get_user_plan($this->workshop->id);
294         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
296         $this->assertCount(0, $result['userplan']['examples']);  // No examples given.
297         $this->assertCount(5, $result['userplan']['phases']);  // Always 5 phases.
298         $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']);  // First phase always setup.
299         $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
301         // Switch phase.
302         $workshop = new workshop($this->workshop, $this->cm, $this->course);
303         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
305         $result = mod_workshop_external::get_user_plan($this->workshop->id);
306         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
308         $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
309         $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
310     }
312     /**
313      * Test mod_workshop_get_user_plan for teachers.
314      */
315     public function test_mod_workshop_get_user_plan_teacher() {
316         global $DB;
318         self::setUser($this->teacher);
319         $result = mod_workshop_external::get_user_plan($this->workshop->id);
320         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
322         $this->assertCount(0, $result['userplan']['examples']);  // No examples given.
323         $this->assertCount(5, $result['userplan']['phases']);  // Always 5 phases.
324         $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']);  // First phase always setup.
325         $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
326         $this->assertCount(4, $result['userplan']['phases'][0]['tasks']);  // For new empty workshops, always 4 tasks.
328         foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
329             if ($task['code'] == 'intro' || $task['code'] == 'instructauthors') {
330                 $this->assertEquals(1, $task['completed']);
331             } else {
332                 $this->assertEmpty($task['completed']);
333             }
334         }
336         // Do some of the tasks asked - switch phase.
337         $workshop = new workshop($this->workshop, $this->cm, $this->course);
338         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
340         $result = mod_workshop_external::get_user_plan($this->workshop->id);
341         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
342         foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
343             if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'switchtonextphase') {
344                 $this->assertEquals(1, $task['completed']);
345             } else {
346                 $this->assertEmpty($task['completed']);
347             }
348         }
350         $result = mod_workshop_external::get_user_plan($this->workshop->id);
351         $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
353         $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
354         $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
355     }
357     /**
358      * Test test_view_workshop invalid id.
359      */
360     public function test_view_workshop_invalid_id() {
361         $this->expectException('moodle_exception');
362         mod_workshop_external::view_workshop(0);
363     }
365     /**
366      * Test test_view_workshop user not enrolled.
367      */
368     public function test_view_workshop_user_not_enrolled() {
369         // Test not-enrolled user.
370         $usernotenrolled = self::getDataGenerator()->create_user();
371         $this->setUser($usernotenrolled);
372         $this->expectException('moodle_exception');
373         mod_workshop_external::view_workshop($this->workshop->id);
374     }
376     /**
377      * Test test_view_workshop user student.
378      */
379     public function test_view_workshop_user_student() {
380         // Test user with full capabilities.
381         $this->setUser($this->student);
383         // Trigger and capture the event.
384         $sink = $this->redirectEvents();
386         $result = mod_workshop_external::view_workshop($this->workshop->id);
387         $result = external_api::clean_returnvalue(mod_workshop_external::view_workshop_returns(), $result);
388         $this->assertTrue($result['status']);
390         $events = $sink->get_events();
391         $this->assertCount(1, $events);
392         $event = array_shift($events);
394         // Checking that the event contains the expected values.
395         $this->assertInstanceOf('\mod_workshop\event\course_module_viewed', $event);
396         $this->assertEquals($this->context, $event->get_context());
397         $moodleworkshop = new \moodle_url('/mod/workshop/view.php', array('id' => $this->cm->id));
398         $this->assertEquals($moodleworkshop, $event->get_url());
399         $this->assertEventContextNotUsed($event);
400         $this->assertNotEmpty($event->get_name());
401     }
403     /**
404      * Test test_view_workshop user missing capabilities.
405      */
406     public function test_view_workshop_user_missing_capabilities() {
407         // Test user with no capabilities.
408         // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
409         assign_capability('mod/workshop:view', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
410         // Empty all the caches that may be affected  by this change.
411         accesslib_clear_all_caches_for_unit_testing();
412         course_modinfo::clear_instance_cache();
414         $this->setUser($this->student);
415         $this->expectException('moodle_exception');
416         mod_workshop_external::view_workshop($this->workshop->id);
417     }
419     /**
420      * Test test_add_submission.
421      */
422     public function test_add_submission() {
423         $fs = get_file_storage();
425         // Test user with full capabilities.
426         $this->setUser($this->student);
428         $title = 'Submission title';
429         $content = 'Submission contents';
431         // Create a file in a draft area for inline attachments.
432         $draftidinlineattach = file_get_unused_draft_itemid();
433         $usercontext = context_user::instance($this->student->id);
434         $filenameimg = 'shouldbeanimage.txt';
435         $filerecordinline = array(
436             'contextid' => $usercontext->id,
437             'component' => 'user',
438             'filearea'  => 'draft',
439             'itemid'    => $draftidinlineattach,
440             'filepath'  => '/',
441             'filename'  => $filenameimg,
442         );
443         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
445         // Create a file in a draft area for regular attachments.
446         $draftidattach = file_get_unused_draft_itemid();
447         $filerecordattach = $filerecordinline;
448         $attachfilename = 'attachment.txt';
449         $filerecordattach['filename'] = $attachfilename;
450         $filerecordattach['itemid'] = $draftidattach;
451         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
453         // Switch to submission phase.
454         $workshop = new workshop($this->workshop, $this->cm, $this->course);
455         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
457         $result = mod_workshop_external::add_submission($this->workshop->id, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
458             $draftidattach);
459         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
460         $this->assertEmpty($result['warnings']);
462         // Check submission created.
463         $submission = $workshop->get_submission_by_author($this->student->id);
464         $this->assertEquals($result['submissionid'], $submission->id);
465         $this->assertEquals($title, $submission->title);
466         $this->assertEquals($content, $submission->content);
468         // Check files.
469         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_content', $submission->id);
470         $this->assertCount(2, $contentfiles);
471         foreach ($contentfiles as $file) {
472             if ($file->is_directory()) {
473                 continue;
474             } else {
475                 $this->assertEquals($filenameimg, $file->get_filename());
476             }
477         }
478         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_attachment', $submission->id);
479         $this->assertCount(2, $contentfiles);
480         foreach ($contentfiles as $file) {
481             if ($file->is_directory()) {
482                 continue;
483             } else {
484                 $this->assertEquals($attachfilename, $file->get_filename());
485             }
486         }
487     }
489     /**
490      * Test test_add_submission invalid phase.
491      */
492     public function test_add_submission_invalid_phase() {
493         $this->setUser($this->student);
495         $this->expectException('moodle_exception');
496         mod_workshop_external::add_submission($this->workshop->id, 'Test');
497     }
499     /**
500      * Test test_add_submission empty title.
501      */
502     public function test_add_submission_empty_title() {
503         $this->setUser($this->student);
505         // Switch to submission phase.
506         $workshop = new workshop($this->workshop, $this->cm, $this->course);
507         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
509         $this->expectException('moodle_exception');
510         mod_workshop_external::add_submission($this->workshop->id, '');
511     }
513     /**
514      * Test test_add_submission already added.
515      */
516     public function test_add_submission_already_added() {
517         $this->setUser($this->student);
519         // Switch to submission phase.
520         $workshop = new workshop($this->workshop, $this->cm, $this->course);
521         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
523         // Create the submission.
524         $result = mod_workshop_external::add_submission($this->workshop->id, 'My submission');
525         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
527         // Try to create it again.
528         $result = mod_workshop_external::add_submission($this->workshop->id, 'My submission');
529         $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
530         $this->assertEquals(0, $result['submissionid']);
531         $this->assertCount(2, $result['warnings']);
532         $this->assertEquals('fielderror', $result['warnings'][0]['warningcode']);
533         $this->assertEquals('content_editor', $result['warnings'][0]['item']);
534         $this->assertEquals('fielderror', $result['warnings'][1]['warningcode']);
535         $this->assertEquals('attachment_filemanager', $result['warnings'][1]['item']);
536     }
538     /**
539      * Helper method to create a submission for testing for the given user.
540      *
541      * @param int $user the submission will be created by this student.
542      * @return int the submission id
543      */
544     protected function create_test_submission($user) {
545         // Test user with full capabilities.
546         $this->setUser($user);
548         $title = 'Submission title';
549         $content = 'Submission contents';
551         // Create a file in a draft area for inline attachments.
552         $fs = get_file_storage();
553         $draftidinlineattach = file_get_unused_draft_itemid();
554         $usercontext = context_user::instance($this->student->id);
555         $filenameimg = 'shouldbeanimage.txt';
556         $filerecordinline = array(
557             'contextid' => $usercontext->id,
558             'component' => 'user',
559             'filearea'  => 'draft',
560             'itemid'    => $draftidinlineattach,
561             'filepath'  => '/',
562             'filename'  => $filenameimg,
563         );
564         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
566         // Create a file in a draft area for regular attachments.
567         $draftidattach = file_get_unused_draft_itemid();
568         $filerecordattach = $filerecordinline;
569         $attachfilename = 'attachment.txt';
570         $filerecordattach['filename'] = $attachfilename;
571         $filerecordattach['itemid'] = $draftidattach;
572         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
574         // Switch to submission phase.
575         $workshop = new workshop($this->workshop, $this->cm, $this->course);
576         $workshop->switch_phase(workshop::PHASE_SUBMISSION);
578         $result = mod_workshop_external::add_submission($this->workshop->id, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
579             $draftidattach);
580         return $result['submissionid'];
581     }
583     /**
584      * Test test_update_submission.
585      */
586     public function test_update_submission() {
588         // Create the submission that will be updated.
589         $submissionid = $this->create_test_submission($this->student);
591         // Test user with full capabilities.
592         $this->setUser($this->student);
594         $title = 'Submission new title';
595         $content = 'Submission new contents';
597         // Create a different file in a draft area for inline attachments.
598         $fs = get_file_storage();
599         $draftidinlineattach = file_get_unused_draft_itemid();
600         $usercontext = context_user::instance($this->student->id);
601         $filenameimg = 'shouldbeanimage_new.txt';
602         $filerecordinline = array(
603             'contextid' => $usercontext->id,
604             'component' => 'user',
605             'filearea'  => 'draft',
606             'itemid'    => $draftidinlineattach,
607             'filepath'  => '/',
608             'filename'  => $filenameimg,
609         );
610         $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
612         // Create a different file in a draft area for regular attachments.
613         $draftidattach = file_get_unused_draft_itemid();
614         $filerecordattach = $filerecordinline;
615         $attachfilename = 'attachment_new.txt';
616         $filerecordattach['filename'] = $attachfilename;
617         $filerecordattach['itemid'] = $draftidattach;
618         $fs->create_file_from_string($filerecordattach, 'simple text attachment');
620         $result = mod_workshop_external::update_submission($submissionid, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
621             $draftidattach);
622         $result = external_api::clean_returnvalue(mod_workshop_external::update_submission_returns(), $result);
623         $this->assertEmpty($result['warnings']);
625         // Check submission updated.
626         $workshop = new workshop($this->workshop, $this->cm, $this->course);
627         $submission = $workshop->get_submission_by_id($submissionid);
628         $this->assertTrue($result['status']);
629         $this->assertEquals($title, $submission->title);
630         $this->assertEquals($content, $submission->content);
632         // Check files.
633         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_content', $submission->id);
634         $this->assertCount(2, $contentfiles);
635         foreach ($contentfiles as $file) {
636             if ($file->is_directory()) {
637                 continue;
638             } else {
639                 $this->assertEquals($filenameimg, $file->get_filename());
640             }
641         }
642         $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_attachment', $submission->id);
643         $this->assertCount(2, $contentfiles);
644         foreach ($contentfiles as $file) {
645             if ($file->is_directory()) {
646                 continue;
647             } else {
648                 $this->assertEquals($attachfilename, $file->get_filename());
649             }
650         }
651     }
653     /**
654      * Test test_update_submission belonging to other user.
655      */
656     public function test_update_submission_of_other_user() {
657         // Create the submission that will be updated.
658         $submissionid = $this->create_test_submission($this->student);
660         $this->setUser($this->teacher);
662         $this->expectException('moodle_exception');
663         mod_workshop_external::update_submission($submissionid, 'Test');
664     }
666     /**
667      * Test test_update_submission invalid phase.
668      */
669     public function test_update_submission_invalid_phase() {
670         // Create the submission that will be updated.
671         $submissionid = $this->create_test_submission($this->student);
673         $this->setUser($this->student);
675         // Switch to assessment phase.
676         $workshop = new workshop($this->workshop, $this->cm, $this->course);
677         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
679         $this->expectException('moodle_exception');
680         mod_workshop_external::update_submission($submissionid, 'Test');
681     }
683     /**
684      * Test test_update_submission empty title.
685      */
686     public function test_update_submission_empty_title() {
687         // Create the submission that will be updated.
688         $submissionid = $this->create_test_submission($this->student);
690         $this->setUser($this->student);
692         $this->expectException('moodle_exception');
693         mod_workshop_external::update_submission($submissionid, '');
694     }
696     /**
697      * Test test_delete_submission.
698      */
699     public function test_delete_submission() {
701         // Create the submission that will be deleted.
702         $submissionid = $this->create_test_submission($this->student);
704         $this->setUser($this->student);
706         // Trigger and capture the event.
707         $sink = $this->redirectEvents();
709         $result = mod_workshop_external::delete_submission($submissionid);
710         $result = external_api::clean_returnvalue(mod_workshop_external::delete_submission_returns(), $result);
711         $this->assertEmpty($result['warnings']);
712         $this->assertTrue($result['status']);
713         $workshop = new workshop($this->workshop, $this->cm, $this->course);
714         $submission = $workshop->get_submission_by_author($this->student->id);
715         $this->assertFalse($submission);
717         $events = $sink->get_events();
718         $this->assertCount(1, $events);
719         $event = array_shift($events);
721         // Checking event.
722         $this->assertInstanceOf('\mod_workshop\event\submission_deleted', $event);
723         $this->assertEquals($this->context, $event->get_context());
724     }
726     /**
727      * Test test_delete_submission_with_assessments.
728      */
729     public function test_delete_submission_with_assessments() {
731         // Create the submission that will be deleted.
732         $submissionid = $this->create_test_submission($this->student);
734         $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
735         $workshopgenerator->create_assessment($submissionid, $this->teacher->id, array(
736             'weight' => 3,
737             'grade' => 95.00000,
738         ));
740         $this->setUser($this->student);
741         $this->expectException('moodle_exception');
742         mod_workshop_external::delete_submission($submissionid);
743     }
745     /**
746      * Test test_delete_submission_invalid_phase.
747      */
748     public function test_delete_submission_invalid_phase() {
750         // Create the submission that will be deleted.
751         $submissionid = $this->create_test_submission($this->student);
753         // Switch to assessment phase.
754         $workshop = new workshop($this->workshop, $this->cm, $this->course);
755         $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
757         $this->setUser($this->student);
758         $this->expectException('moodle_exception');
759         mod_workshop_external::delete_submission($submissionid);
760     }
762     /**
763      * Test test_delete_submission_as_teacher.
764      */
765     public function test_delete_submission_as_teacher() {
767         // Create the submission that will be deleted.
768         $submissionid = $this->create_test_submission($this->student);
770         $this->setUser($this->teacher);
771         $result = mod_workshop_external::delete_submission($submissionid);
772         $result = external_api::clean_returnvalue(mod_workshop_external::delete_submission_returns(), $result);
773         $this->assertEmpty($result['warnings']);
774         $this->assertTrue($result['status']);
775     }
777     /**
778      * Test test_delete_submission_other_user.
779      */
780     public function test_delete_submission_other_user() {
782         $anotheruser = self::getDataGenerator()->create_user();
783         $this->getDataGenerator()->enrol_user($anotheruser->id, $this->course->id, $this->studentrole->id, 'manual');
784         // Create the submission that will be deleted.
785         $submissionid = $this->create_test_submission($this->student);
787         $this->setUser($anotheruser);
788         $this->expectException('moodle_exception');
789         mod_workshop_external::delete_submission($submissionid);
790     }