MDL-59243 mod_workshop: Move submission creation to API
[moodle.git] / mod / workshop / tests / external_test.php
CommitLineData
9f1ab2db
JL
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
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 */
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
30
31require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32require_once($CFG->dirroot . '/mod/workshop/lib.php');
33
34use mod_workshop\external\workshop_summary_exporter;
35
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 */
45class mod_workshop_external_testcase extends externallib_advanced_testcase {
46
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;
63
64 /**
65 * Set up for every test
66 */
67 public function setUp() {
68 global $DB;
69 $this->resetAfterTest();
70 $this->setAdminUser();
71
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);
77
78 // Create users.
79 $this->student = self::getDataGenerator()->create_user();
80 $this->teacher = self::getDataGenerator()->create_user();
81
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 }
88
89 /**
90 * Test test_mod_workshop_get_workshops_by_courses
91 */
92 public function test_mod_workshop_get_workshops_by_courses() {
93 global $DB;
94
95 // Create additional course.
96 $course2 = self::getDataGenerator()->create_course();
97
98 // Second workshop.
99 $record = new stdClass();
100 $record->course = $course2->id;
101 $workshop2 = self::getDataGenerator()->create_module('workshop', $record);
102
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);
113
114 self::setUser($this->student);
115
116 $returndescription = mod_workshop_external::get_workshops_by_courses_returns();
117
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);
121
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;
133
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;
143
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 }
152
153 $expectedworkshops = array($expected2, $expected1);
154
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);
158
159 $this->assertEquals($expectedworkshops, $result['workshops']);
160 $this->assertCount(0, $result['warnings']);
161
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']);
167
168 // Unenrol user from second course and alter expected workshops.
169 $enrol->unenrol_user($instance2, $this->student->id);
170 array_shift($expectedworkshops);
171
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']);
176
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 }
977fdfa3
JL
183
184 /**
185 * Test mod_workshop_get_workshop_access_information for students.
186 */
187 public function test_mod_workshop_get_workshop_access_information_student() {
188
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');
195
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();
212
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 }
225
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
232 // Switch phase.
233 $workshop = new workshop($this->workshop, $this->cm, $this->course);
234 $workshop->switch_phase(workshop::PHASE_SUBMISSION);
235 $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
236 $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
237
238 $this->assertTrue($result['creatingsubmissionallowed']);
239 $this->assertTrue($result['modifyingsubmissionallowed']);
240 $this->assertFalse($result['assessingallowed']);
241 $this->assertFalse($result['assessingexamplesallowed']);
242
243 // Switch to next (to assessment).
244 $workshop = new workshop($this->workshop, $this->cm, $this->course);
245 $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
246 $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
247 $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
248
249 $this->assertFalse($result['creatingsubmissionallowed']);
250 $this->assertFalse($result['modifyingsubmissionallowed']);
251 $this->assertTrue($result['assessingallowed']);
252 $this->assertFalse($result['assessingexamplesallowed']);
253 }
254
255 /**
256 * Test mod_workshop_get_workshop_access_information for teachers.
257 */
258 public function test_mod_workshop_get_workshop_access_information_teacher() {
259
260 self::setUser($this->teacher);
261 $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
262 $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
263 // Check default values.
264 $disabledcaps = array('canpeerassess', 'cansubmit');
265
266 foreach ($result as $capname => $capvalue) {
267 if (strpos($capname, 'can') !== 0) {
268 continue;
269 }
270 if (in_array($capname, $disabledcaps)) {
271 $this->assertFalse($capvalue);
272 } else {
273 $this->assertTrue($capvalue);
274 }
275 }
276
277 // Now, specific functionalities.
278 $this->assertFalse($result['creatingsubmissionallowed']);
279 $this->assertFalse($result['modifyingsubmissionallowed']);
280 $this->assertFalse($result['assessingallowed']);
281 $this->assertFalse($result['assessingexamplesallowed']);
282 }
cd495029
JL
283
284 /**
285 * Test mod_workshop_get_user_plan for students.
286 */
287 public function test_mod_workshop_get_user_plan_student() {
288
289 self::setUser($this->student);
290 $result = mod_workshop_external::get_user_plan($this->workshop->id);
291 $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
292
293 $this->assertCount(0, $result['userplan']['examples']); // No examples given.
294 $this->assertCount(5, $result['userplan']['phases']); // Always 5 phases.
295 $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']); // First phase always setup.
296 $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
297
298 // Switch phase.
299 $workshop = new workshop($this->workshop, $this->cm, $this->course);
300 $workshop->switch_phase(workshop::PHASE_SUBMISSION);
301
302 $result = mod_workshop_external::get_user_plan($this->workshop->id);
303 $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
304
305 $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
306 $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
307 }
308
309 /**
310 * Test mod_workshop_get_user_plan for teachers.
311 */
312 public function test_mod_workshop_get_user_plan_teacher() {
313 global $DB;
314
315 self::setUser($this->teacher);
316 $result = mod_workshop_external::get_user_plan($this->workshop->id);
317 $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
318
319 $this->assertCount(0, $result['userplan']['examples']); // No examples given.
320 $this->assertCount(5, $result['userplan']['phases']); // Always 5 phases.
321 $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']); // First phase always setup.
322 $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
323 $this->assertCount(4, $result['userplan']['phases'][0]['tasks']); // For new empty workshops, always 4 tasks.
324
325 foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
326 if ($task['code'] == 'intro' || $task['code'] == 'instructauthors') {
327 $this->assertEquals(1, $task['completed']);
328 } else {
329 $this->assertEmpty($task['completed']);
330 }
331 }
332
333 // Do some of the tasks asked - switch phase.
334 $workshop = new workshop($this->workshop, $this->cm, $this->course);
335 $workshop->switch_phase(workshop::PHASE_SUBMISSION);
336
337 $result = mod_workshop_external::get_user_plan($this->workshop->id);
338 $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
339 foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
340 if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'switchtonextphase') {
341 $this->assertEquals(1, $task['completed']);
342 } else {
343 $this->assertEmpty($task['completed']);
344 }
345 }
346
347 $result = mod_workshop_external::get_user_plan($this->workshop->id);
348 $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
349
350 $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
351 $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
352 }
291645f7
JL
353
354 /**
355 * Test test_view_workshop invalid id.
356 */
357 public function test_view_workshop_invalid_id() {
358 $this->expectException('moodle_exception');
359 mod_workshop_external::view_workshop(0);
360 }
361
362 /**
363 * Test test_view_workshop user not enrolled.
364 */
365 public function test_view_workshop_user_not_enrolled() {
366 // Test not-enrolled user.
367 $usernotenrolled = self::getDataGenerator()->create_user();
368 $this->setUser($usernotenrolled);
369 $this->expectException('moodle_exception');
370 mod_workshop_external::view_workshop($this->workshop->id);
371 }
372
373 /**
374 * Test test_view_workshop user student.
375 */
376 public function test_view_workshop_user_student() {
377 // Test user with full capabilities.
378 $this->setUser($this->student);
379
380 // Trigger and capture the event.
381 $sink = $this->redirectEvents();
382
383 $result = mod_workshop_external::view_workshop($this->workshop->id);
384 $result = external_api::clean_returnvalue(mod_workshop_external::view_workshop_returns(), $result);
385 $this->assertTrue($result['status']);
386
387 $events = $sink->get_events();
388 $this->assertCount(1, $events);
389 $event = array_shift($events);
390
391 // Checking that the event contains the expected values.
392 $this->assertInstanceOf('\mod_workshop\event\course_module_viewed', $event);
393 $this->assertEquals($this->context, $event->get_context());
394 $moodleworkshop = new \moodle_url('/mod/workshop/view.php', array('id' => $this->cm->id));
395 $this->assertEquals($moodleworkshop, $event->get_url());
396 $this->assertEventContextNotUsed($event);
397 $this->assertNotEmpty($event->get_name());
398 }
399
400 /**
401 * Test test_view_workshop user missing capabilities.
402 */
403 public function test_view_workshop_user_missing_capabilities() {
404 // Test user with no capabilities.
405 // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
406 assign_capability('mod/workshop:view', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
407 // Empty all the caches that may be affected by this change.
408 accesslib_clear_all_caches_for_unit_testing();
409 course_modinfo::clear_instance_cache();
410
411 $this->setUser($this->student);
412 $this->expectException('moodle_exception');
413 mod_workshop_external::view_workshop($this->workshop->id);
414 }
9f1ab2db 415}