Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

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