Proyectos de Subversion Moodle

Rev

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