Proyectos de Subversion Moodle

Rev

| 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 external API
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
defined('MOODLE_INTERNAL') || die;
28
 
29
require_once($CFG->dirroot . '/mod/workshop/locallib.php');
30
 
31
use core_external\external_api;
32
use core_external\external_files;
33
use core_external\external_function_parameters;
34
use core_external\external_multiple_structure;
35
use core_external\external_single_structure;
36
use core_external\external_value;
37
use core_external\external_warnings;
38
use core_external\util;
39
use mod_workshop\external\workshop_summary_exporter;
40
use mod_workshop\external\submission_exporter;
41
use mod_workshop\external\assessment_exporter;
42
 
43
/**
44
 * Workshop external functions
45
 *
46
 * @package    mod_workshop
47
 * @category   external
48
 * @copyright  2017 Juan Leyva <juan@moodle.com>
49
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
50
 * @since      Moodle 3.4
51
 */
52
class mod_workshop_external extends external_api {
53
 
54
    /**
55
     * Describes the parameters for get_workshops_by_courses.
56
     *
57
     * @return external_function_parameters
58
     * @since Moodle 3.4
59
     */
60
    public static function get_workshops_by_courses_parameters() {
61
        return new external_function_parameters (
62
            array(
63
                'courseids' => new external_multiple_structure(
64
                    new external_value(PARAM_INT, 'Course id'), 'Array of course ids', VALUE_DEFAULT, array()
65
                ),
66
            )
67
        );
68
    }
69
 
70
    /**
71
     * Returns a list of workshops in a provided list of courses.
72
     * If no list is provided all workshops that the user can view will be returned.
73
     *
74
     * @param array $courseids course ids
75
     * @return array of warnings and workshops
76
     * @since Moodle 3.4
77
     */
78
    public static function get_workshops_by_courses($courseids = array()) {
79
        global $PAGE;
80
 
81
        $warnings = array();
82
        $returnedworkshops = array();
83
 
84
        $params = array(
85
            'courseids' => $courseids,
86
        );
87
        $params = self::validate_parameters(self::get_workshops_by_courses_parameters(), $params);
88
 
89
        $mycourses = array();
90
        if (empty($params['courseids'])) {
91
            $mycourses = enrol_get_my_courses();
92
            $params['courseids'] = array_keys($mycourses);
93
        }
94
 
95
        // Ensure there are courseids to loop through.
96
        if (!empty($params['courseids'])) {
97
 
98
            list($courses, $warnings) = util::validate_courses($params['courseids'], $mycourses);
99
            $output = $PAGE->get_renderer('core');
100
 
101
            // Get the workshops in this course, this function checks users visibility permissions.
102
            // We can avoid then additional validate_context calls.
103
            $workshops = get_all_instances_in_courses("workshop", $courses);
104
            foreach ($workshops as $workshop) {
105
 
106
                $context = context_module::instance($workshop->coursemodule);
107
                // Remove fields that are not from the workshop (added by get_all_instances_in_courses).
108
                unset($workshop->coursemodule, $workshop->context, $workshop->visible, $workshop->section, $workshop->groupmode,
109
                        $workshop->groupingid);
110
 
111
                $exporter = new workshop_summary_exporter($workshop, array('context' => $context));
112
                $returnedworkshops[] = $exporter->export($output);
113
            }
114
        }
115
 
116
        $result = array(
117
            'workshops' => $returnedworkshops,
118
            'warnings' => $warnings
119
        );
120
        return $result;
121
    }
122
 
123
    /**
124
     * Describes the get_workshops_by_courses return value.
125
     *
126
     * @return external_single_structure
127
     * @since Moodle 3.4
128
     */
129
    public static function get_workshops_by_courses_returns() {
130
        return new external_single_structure(
131
            array(
132
                'workshops' => new external_multiple_structure(
133
                    workshop_summary_exporter::get_read_structure()
134
                ),
135
                'warnings' => new external_warnings(),
136
            )
137
        );
138
    }
139
 
140
    /**
141
     * Utility function for validating a workshop.
142
     *
143
     * @param int $workshopid workshop instance id
144
     * @return array array containing the workshop object, course, context and course module objects
145
     * @since  Moodle 3.4
146
     */
147
    protected static function validate_workshop($workshopid) {
148
        global $DB, $USER;
149
 
150
        // Request and permission validation.
151
        $workshop = $DB->get_record('workshop', array('id' => $workshopid), '*', MUST_EXIST);
152
        list($course, $cm) = get_course_and_cm_from_instance($workshop, 'workshop');
153
 
154
        $context = context_module::instance($cm->id);
155
        self::validate_context($context);
156
 
157
        $workshop = new workshop($workshop, $cm, $course);
158
 
159
        return array($workshop, $course, $cm, $context);
160
    }
161
 
162
 
163
    /**
164
     * Describes the parameters for get_workshop_access_information.
165
     *
166
     * @return external_external_function_parameters
167
     * @since Moodle 3.4
168
     */
169
    public static function get_workshop_access_information_parameters() {
170
        return new external_function_parameters (
171
            array(
172
                'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.')
173
            )
174
        );
175
    }
176
 
177
    /**
178
     * Return access information for a given workshop.
179
     *
180
     * @param int $workshopid workshop instance id
181
     * @return array of warnings and the access information
182
     * @since Moodle 3.4
183
     * @throws  moodle_exception
184
     */
185
    public static function get_workshop_access_information($workshopid) {
186
        global $USER;
187
 
188
        $params = self::validate_parameters(self::get_workshop_access_information_parameters(), array('workshopid' => $workshopid));
189
 
190
        list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
191
 
192
        $result = array();
193
        // Return all the available capabilities.
194
        $capabilities = load_capability_def('mod_workshop');
195
        foreach ($capabilities as $capname => $capdata) {
196
            // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules.
197
            $field = 'can' . str_replace('mod/workshop:', '', $capname);
198
            $result[$field] = has_capability($capname, $context);
199
        }
200
 
201
        // Now, specific features access information.
202
        $result['creatingsubmissionallowed'] = $workshop->creating_submission_allowed($USER->id);
203
        $result['modifyingsubmissionallowed'] = $workshop->modifying_submission_allowed($USER->id);
204
        $result['assessingallowed'] = $workshop->assessing_allowed($USER->id);
205
        $result['assessingexamplesallowed'] = $workshop->assessing_examples_allowed();
206
        if (is_null($result['assessingexamplesallowed'])) {
207
            $result['assessingexamplesallowed'] = false;
208
        }
209
        $result['examplesassessedbeforesubmission'] = $workshop->check_examples_assessed_before_submission($USER->id);
210
        list($result['examplesassessedbeforeassessment'], $code) = $workshop->check_examples_assessed_before_assessment($USER->id);
211
 
212
        $result['warnings'] = array();
213
        return $result;
214
    }
215
 
216
    /**
217
     * Describes the get_workshop_access_information return value.
218
     *
219
     * @return external_single_structure
220
     * @since Moodle 3.4
221
     */
222
    public static function get_workshop_access_information_returns() {
223
 
224
        $structure = array(
225
            'creatingsubmissionallowed' => new external_value(PARAM_BOOL,
226
                'Is the given user allowed to create their submission?'),
227
            'modifyingsubmissionallowed' => new external_value(PARAM_BOOL,
228
                'Is the user allowed to modify his existing submission?'),
229
            'assessingallowed' => new external_value(PARAM_BOOL,
230
                'Is the user allowed to create/edit his assessments?'),
231
            'assessingexamplesallowed' => new external_value(PARAM_BOOL,
232
                'Are reviewers allowed to create/edit their assessments of the example submissions?.'),
233
            'examplesassessedbeforesubmission' => new external_value(PARAM_BOOL,
234
                'Whether the given user has assessed all his required examples before submission
235
                (always true if there are not examples to assess or not configured to check before submission).'),
236
            'examplesassessedbeforeassessment' => new external_value(PARAM_BOOL,
237
                'Whether the given user has assessed all his required examples before assessment
238
                (always true if there are not examples to assessor not configured to check before assessment).'),
239
            'warnings' => new external_warnings()
240
        );
241
 
242
        $capabilities = load_capability_def('mod_workshop');
243
        foreach ($capabilities as $capname => $capdata) {
244
            // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules.
245
            $field = 'can' . str_replace('mod/workshop:', '', $capname);
246
            $structure[$field] = new external_value(PARAM_BOOL, 'Whether the user has the capability ' . $capname . ' allowed.');
247
        }
248
 
249
        return new external_single_structure($structure);
250
    }
251
 
252
    /**
253
     * Describes the parameters for get_user_plan.
254
     *
255
     * @return external_external_function_parameters
256
     * @since Moodle 3.4
257
     */
258
    public static function get_user_plan_parameters() {
259
        return new external_function_parameters (
260
            array(
261
                'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
262
                'userid' => new external_value(PARAM_INT, 'User id (empty or 0 for current user).', VALUE_DEFAULT, 0),
263
            )
264
        );
265
    }
266
 
267
    /**
268
     * Return the planner information for the given user.
269
     *
270
     * @param int $workshopid workshop instance id
271
     * @param int $userid user id
272
     * @return array of warnings and the user plan
273
     * @since Moodle 3.4
274
     * @throws  moodle_exception
275
     */
276
    public static function get_user_plan($workshopid, $userid = 0) {
277
        global $USER;
278
 
279
        $params = array(
280
            'workshopid' => $workshopid,
281
            'userid' => $userid,
282
        );
283
        $params = self::validate_parameters(self::get_user_plan_parameters(), $params);
284
 
285
        list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
286
 
287
        // Extra checks so only users with permissions can view other users plans.
288
        if (empty($params['userid']) || $params['userid'] == $USER->id) {
289
            $userid = $USER->id;
290
        } else {
291
            require_capability('moodle/course:manageactivities', $context);
292
            $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
293
            core_user::require_active_user($user);
294
            if (!$workshop->check_group_membership($user->id)) {
295
                throw new moodle_exception('notingroup');
296
            }
297
            $userid = $user->id;
298
        }
299
 
300
        // Get the user plan information ready for external functions.
301
        $userplan = new workshop_user_plan($workshop, $userid);
302
        $userplan = array('phases' => $userplan->phases, 'examples' => $userplan->get_examples());
303
        foreach ($userplan['phases'] as $phasecode => $phase) {
304
            $phase->code = $phasecode;
305
            $userplan['phases'][$phasecode] = (array) $phase;
306
            foreach ($userplan['phases'][$phasecode]['tasks'] as $taskcode => $task) {
307
                $task->code = $taskcode;
308
                if ($task->link instanceof moodle_url) {
309
                    $task->link = $task->link->out(false);
310
                }
311
                $userplan['phases'][$phasecode]['tasks'][$taskcode] = (array) $task;
312
            }
313
            foreach ($userplan['phases'][$phasecode]['actions'] as $actioncode => $action) {
314
                if ($action->url instanceof moodle_url) {
315
                    $action->url = $action->url->out(false);
316
                }
317
                $userplan['phases'][$phasecode]['actions'][$actioncode] = (array) $action;
318
            }
319
        }
320
 
321
        $result['userplan'] = $userplan;
322
        $result['warnings'] = array();
323
        return $result;
324
    }
325
 
326
    /**
327
     * Describes the get_user_plan return value.
328
     *
329
     * @return external_single_structure
330
     * @since Moodle 3.4
331
     */
332
    public static function get_user_plan_returns() {
333
        return new external_single_structure(
334
            array(
335
                'userplan' => new external_single_structure(
336
                    array(
337
                        'phases' => new external_multiple_structure(
338
                            new external_single_structure(
339
                                array(
340
                                    'code' => new external_value(PARAM_INT, 'Phase code.'),
341
                                    'title' => new external_value(PARAM_NOTAGS, 'Phase title.'),
342
                                    'active' => new external_value(PARAM_BOOL, 'Whether is the active task.'),
343
                                    'tasks' => new external_multiple_structure(
344
                                        new external_single_structure(
345
                                            array(
346
                                                'code' => new external_value(PARAM_ALPHA, 'Task code.'),
347
                                                'title' => new external_value(PARAM_RAW, 'Task title.'),
348
                                                'link' => new external_value(PARAM_URL, 'Link to task.'),
349
                                                'details' => new external_value(PARAM_RAW, 'Task details.', VALUE_OPTIONAL),
350
                                                'completed' => new external_value(PARAM_NOTAGS,
351
                                                    'Completion information (maybe empty, maybe a boolean or generic info.'),
352
                                            )
353
                                        )
354
                                    ),
355
                                    'actions' => new external_multiple_structure(
356
                                        new external_single_structure(
357
                                            array(
358
                                                'type' => new external_value(PARAM_ALPHA, 'Action type.', VALUE_OPTIONAL),
359
                                                'label' => new external_value(PARAM_RAW, 'Action label.', VALUE_OPTIONAL),
360
                                                'url' => new external_value(PARAM_URL, 'Link to action.'),
361
                                                'method' => new external_value(PARAM_ALPHA, 'Get or post.', VALUE_OPTIONAL),
362
                                            )
363
                                        )
364
                                    ),
365
                                )
366
                            )
367
                        ),
368
                        'examples' => new external_multiple_structure(
369
                            new external_single_structure(
370
                                array(
371
                                    'id' => new external_value(PARAM_INT, 'Example submission id.'),
372
                                    'title' => new external_value(PARAM_RAW, 'Example submission title.'),
373
                                    'assessmentid' => new external_value(PARAM_INT, 'Example submission assessment id.'),
374
                                    'grade' => new external_value(PARAM_FLOAT, 'The submission grade.'),
375
                                    'gradinggrade' => new external_value(PARAM_FLOAT, 'The assessment grade.'),
376
                                )
377
                            )
378
                        ),
379
                    )
380
                ),
381
                'warnings' => new external_warnings(),
382
            )
383
        );
384
    }
385
 
386
    /**
387
     * Describes the parameters for view_workshop.
388
     *
389
     * @return external_function_parameters
390
     * @since Moodle 3.4
391
     */
392
    public static function view_workshop_parameters() {
393
        return new external_function_parameters (
394
            array(
395
                'workshopid' => new external_value(PARAM_INT, 'Workshop instance id'),
396
            )
397
        );
398
    }
399
 
400
    /**
401
     * Trigger the course module viewed event and update the module completion status.
402
     *
403
     * @param int $workshopid workshop instance id
404
     * @return array of warnings and status result
405
     * @since Moodle 3.4
406
     * @throws moodle_exception
407
     */
408
    public static function view_workshop($workshopid) {
409
 
410
        $params = array('workshopid' => $workshopid);
411
        $params = self::validate_parameters(self::view_workshop_parameters(), $params);
412
        $warnings = array();
413
 
414
        list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
415
 
416
        $workshop->set_module_viewed();
417
 
418
        $result = array(
419
            'status' => true,
420
            'warnings' => $warnings,
421
        );
422
        return $result;
423
    }
424
 
425
    /**
426
     * Describes the view_workshop return value.
427
     *
428
     * @return external_single_structure
429
     * @since Moodle 3.4
430
     */
431
    public static function view_workshop_returns() {
432
        return new external_single_structure(
433
            array(
434
                'status' => new external_value(PARAM_BOOL, 'status: true if success'),
435
                'warnings' => new external_warnings(),
436
            )
437
        );
438
    }
439
 
440
    /**
441
     * Returns the description of the external function parameters.
442
     *
443
     * @return external_function_parameters
444
     * @since Moodle 3.4
445
     */
446
    public static function add_submission_parameters() {
447
        return new external_function_parameters(array(
448
            'workshopid' => new external_value(PARAM_INT, 'Workshop id'),
449
            'title' => new external_value(PARAM_TEXT, 'Submission title'),
450
            'content' => new external_value(PARAM_RAW, 'Submission text content', VALUE_DEFAULT, ''),
451
            'contentformat' => new external_value(PARAM_INT, 'The format used for the content', VALUE_DEFAULT, FORMAT_MOODLE),
452
            'inlineattachmentsid' => new external_value(PARAM_INT, 'The draft file area id for inline attachments in the content',
453
                VALUE_DEFAULT, 0),
454
            'attachmentsid' => new external_value(PARAM_INT, 'The draft file area id for attachments', VALUE_DEFAULT, 0),
455
        ));
456
    }
457
 
458
    /**
459
     * Add a new submission to a given workshop.
460
     *
461
     * @param int $workshopid the workshop id
462
     * @param string $title             the submission title
463
     * @param string  $content          the submission text content
464
     * @param int  $contentformat       the format used for the content
465
     * @param int $inlineattachmentsid  the draft file area id for inline attachments in the content
466
     * @param int $attachmentsid        the draft file area id for attachments
467
     * @return array Containing the new created submission id and warnings.
468
     * @since Moodle 3.4
469
     * @throws moodle_exception
470
     */
471
    public static function add_submission($workshopid, $title, $content = '', $contentformat = FORMAT_MOODLE,
472
            $inlineattachmentsid = 0, $attachmentsid = 0) {
473
        global $USER;
474
 
475
        $params = self::validate_parameters(self::add_submission_parameters(), array(
476
            'workshopid' => $workshopid,
477
            'title' => $title,
478
            'content' => $content,
479
            'contentformat' => $contentformat,
480
            'inlineattachmentsid' => $inlineattachmentsid,
481
            'attachmentsid' => $attachmentsid,
482
        ));
483
        $warnings = array();
484
 
485
        // Get and validate the workshop.
486
        list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
487
        require_capability('mod/workshop:submit', $context);
488
 
489
        // Check if we can submit now.
490
        $canaddsubmission = $workshop->creating_submission_allowed($USER->id);
491
        $canaddsubmission = $canaddsubmission && $workshop->check_examples_assessed_before_submission($USER->id);
492
        if (!$canaddsubmission) {
493
            throw new moodle_exception('nopermissions', 'error', '', 'add submission');
494
        }
495
 
496
        // Prepare the submission object.
497
        $submission = new stdClass;
498
        $submission->id = null;
499
        $submission->cmid = $cm->id;
500
        $submission->example = 0;
501
        $submission->title = trim($params['title']);
502
        $submission->content_editor = array(
503
            'text' => $params['content'],
504
            'format' => $params['contentformat'],
505
            'itemid' => $params['inlineattachmentsid'],
506
        );
507
        $submission->attachment_filemanager = $params['attachmentsid'];
508
 
509
        if (empty($submission->title)) {
510
            throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title');
511
        }
512
 
513
        $errors = $workshop->validate_submission_data((array) $submission);
514
        // We can get several errors, return them in warnings.
515
        if (!empty($errors)) {
516
            $submission->id = 0;
517
            foreach ($errors as $itemname => $message) {
518
                $warnings[] = array(
519
                    'item' => $itemname,
520
                    'itemid' => 0,
521
                    'warningcode' => 'fielderror',
522
                    'message' => s($message)
523
                );
524
            }
525
            return array(
526
                'status' => false,
527
                'warnings' => $warnings
528
            );
529
        } else {
530
            $submission->id = $workshop->edit_submission($submission);
531
            return array(
532
                'status' => true,
533
                'submissionid' => $submission->id,
534
                'warnings' => $warnings
535
            );
536
        }
537
    }
538
 
539
    /**
540
     * Returns the description of the external function return value.
541
     *
542
     * @return \core_external\external_description
543
     * @since Moodle 3.4
544
     */
545
    public static function add_submission_returns() {
546
        return new external_single_structure(array(
547
            'status' => new external_value(PARAM_BOOL, 'True if the submission was created false otherwise.'),
548
            'submissionid' => new external_value(PARAM_INT, 'New workshop submission id.', VALUE_OPTIONAL),
549
            'warnings' => new external_warnings()
550
        ));
551
    }
552
 
553
    /**
554
     * Returns the description of the external function parameters.
555
     *
556
     * @return external_function_parameters
557
     * @since Moodle 3.4
558
     */
559
    public static function update_submission_parameters() {
560
        return new external_function_parameters(array(
561
            'submissionid' => new external_value(PARAM_INT, 'Submission id'),
562
            'title' => new external_value(PARAM_TEXT, 'Submission title'),
563
            'content' => new external_value(PARAM_RAW, 'Submission text content', VALUE_DEFAULT, ''),
564
            'contentformat' => new external_value(PARAM_INT, 'The format used for the content', VALUE_DEFAULT, FORMAT_MOODLE),
565
            'inlineattachmentsid' => new external_value(PARAM_INT, 'The draft file area id for inline attachments in the content',
566
                VALUE_DEFAULT, 0),
567
            'attachmentsid' => new external_value(PARAM_INT, 'The draft file area id for attachments', VALUE_DEFAULT, 0),
568
        ));
569
    }
570
 
571
 
572
    /**
573
     * Updates the given submission.
574
     *
575
     * @param int $submissionid         the submission id
576
     * @param string $title             the submission title
577
     * @param string  $content          the submission text content
578
     * @param int  $contentformat       the format used for the content
579
     * @param int $inlineattachmentsid  the draft file area id for inline attachments in the content
580
     * @param int $attachmentsid        the draft file area id for attachments
581
     * @return array whether the submission was updated and warnings.
582
     * @since Moodle 3.4
583
     * @throws moodle_exception
584
     */
585
    public static function update_submission($submissionid, $title, $content = '', $contentformat = FORMAT_MOODLE,
586
            $inlineattachmentsid = 0, $attachmentsid = 0) {
587
        global $USER, $DB;
588
 
589
        $params = self::validate_parameters(self::update_submission_parameters(), array(
590
            'submissionid' => $submissionid,
591
            'title' => $title,
592
            'content' => $content,
593
            'contentformat' => $contentformat,
594
            'inlineattachmentsid' => $inlineattachmentsid,
595
            'attachmentsid' => $attachmentsid,
596
        ));
597
        $warnings = array();
598
 
599
        // Get and validate the submission and workshop.
600
        $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
601
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
602
        require_capability('mod/workshop:submit', $context);
603
 
604
        // Check if we can update the submission.
605
        $canupdatesubmission = $submission->authorid == $USER->id;
606
        $canupdatesubmission = $canupdatesubmission && $workshop->modifying_submission_allowed($USER->id);
607
        $canupdatesubmission = $canupdatesubmission && $workshop->check_examples_assessed_before_submission($USER->id);
608
        if (!$canupdatesubmission) {
609
            throw new moodle_exception('nopermissions', 'error', '', 'update submission');
610
        }
611
 
612
        // Prepare the submission object.
613
        $submission->title = trim($params['title']);
614
        if (empty($submission->title)) {
615
            throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title');
616
        }
617
        $submission->content_editor = array(
618
            'text' => $params['content'],
619
            'format' => $params['contentformat'],
620
            'itemid' => $params['inlineattachmentsid'],
621
        );
622
        $submission->attachment_filemanager = $params['attachmentsid'];
623
 
624
        $errors = $workshop->validate_submission_data((array) $submission);
625
        // We can get several errors, return them in warnings.
626
        if (!empty($errors)) {
627
            $status = false;
628
            foreach ($errors as $itemname => $message) {
629
                $warnings[] = array(
630
                    'item' => $itemname,
631
                    'itemid' => 0,
632
                    'warningcode' => 'fielderror',
633
                    'message' => s($message)
634
                );
635
            }
636
        } else {
637
            $status = true;
638
            $submission->id = $workshop->edit_submission($submission);
639
        }
640
 
641
        return array(
642
            'status' => $status,
643
            'warnings' => $warnings
644
        );
645
    }
646
 
647
    /**
648
     * Returns the description of the external function return value.
649
     *
650
     * @return \core_external\external_description
651
     * @since Moodle 3.4
652
     */
653
    public static function update_submission_returns() {
654
        return new external_single_structure(array(
655
            'status' => new external_value(PARAM_BOOL, 'True if the submission was updated false otherwise.'),
656
            'warnings' => new external_warnings()
657
        ));
658
    }
659
 
660
    /**
661
     * Returns the description of the external function parameters.
662
     *
663
     * @return external_function_parameters
664
     * @since Moodle 3.4
665
     */
666
    public static function delete_submission_parameters() {
667
        return new external_function_parameters(
668
            array(
669
                'submissionid' => new external_value(PARAM_INT, 'Submission id'),
670
            )
671
        );
672
    }
673
 
674
 
675
    /**
676
     * Deletes the given submission.
677
     *
678
     * @param int $submissionid the submission id.
679
     * @return array containing the result status and warnings.
680
     * @since Moodle 3.4
681
     * @throws moodle_exception
682
     */
683
    public static function delete_submission($submissionid) {
684
        global $USER, $DB;
685
 
686
        $params = self::validate_parameters(self::delete_submission_parameters(), array('submissionid' => $submissionid));
687
        $warnings = array();
688
 
689
        // Get and validate the submission and workshop.
690
        $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
691
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
692
 
693
        // Check if we can delete the submission.
694
        if (!has_capability('mod/workshop:deletesubmissions', $context)) {
695
            require_capability('mod/workshop:submit', $context);
696
            // We can delete our own submission, on time and not yet assessed.
697
            $candeletesubmission = $submission->authorid == $USER->id;
698
            $candeletesubmission = $candeletesubmission && $workshop->modifying_submission_allowed($USER->id);
699
            $candeletesubmission = $candeletesubmission && count($workshop->get_assessments_of_submission($submission->id)) == 0;
700
            if (!$candeletesubmission) {
701
                throw new moodle_exception('nopermissions', 'error', '', 'delete submission');
702
            }
703
        }
704
 
705
        $workshop->delete_submission($submission);
706
 
707
        return array(
708
            'status' => true,
709
            'warnings' => $warnings
710
        );
711
    }
712
 
713
    /**
714
     * Returns the description of the external function return value.
715
     *
716
     * @return \core_external\external_description
717
     * @since Moodle 3.4
718
     */
719
    public static function delete_submission_returns() {
720
        return new external_single_structure(array(
721
            'status' => new external_value(PARAM_BOOL, 'True if the submission was deleted.'),
722
            'warnings' => new external_warnings()
723
        ));
724
    }
725
 
726
    /**
727
     * Helper method for returning the submission data according the current user capabilities and current phase.
728
     *
729
     * @param  stdClass $submission the submission data
730
     * @param  workshop $workshop   the workshop class
731
     * @param  bool $canviewauthorpublished whether the user has the capability mod/workshop:viewauthorpublished on
732
     * @param  bool $canviewauthornames whether the user has the capability mod/workshop:vviewauthornames on
733
     * @param  bool $canviewallsubmissions whether the user has the capability mod/workshop:viewallsubmissions on
734
     * @return stdClass object with the submission data filtered
735
     * @since Moodle 3.4
736
     */
737
    protected static function prepare_submission_for_external($submission, workshop $workshop, $canviewauthorpublished = null,
738
            $canviewauthornames = null, $canviewallsubmissions = null) {
739
        global $USER;
740
 
741
        if (is_null($canviewauthorpublished)) {
742
            $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $workshop->context);
743
        }
744
        if (is_null($canviewauthornames)) {
745
            $canviewauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context);
746
        }
747
        if (is_null($canviewallsubmissions)) {
748
            $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $workshop->context);
749
        }
750
 
751
        $ownsubmission = $submission->authorid == $USER->id;
752
        if (!$canviewauthornames && !$ownsubmission) {
753
            $submission->authorid = 0;
754
        }
755
 
756
        // Remove grade, gradeover, gradeoverby, feedbackauthor and timegraded for non-teachers or invalid phase.
757
        // WS mod_workshop_external::get_grades should be used for retrieving grades by students.
758
        if ($workshop->phase < workshop::PHASE_EVALUATION || !$canviewallsubmissions) {
759
            $properties = submission_exporter::properties_definition();
760
            foreach ($properties as $attribute => $settings) {
761
                // Special case, the feedbackauthor (and who did it) should be returned if the workshop is closed and
762
                // the user can view it.
763
                if (($attribute == 'feedbackauthor' || $attribute == 'gradeoverby') &&
764
                        $workshop->phase == workshop::PHASE_CLOSED && $ownsubmission) {
765
                    continue;
766
                }
767
                if (!empty($settings['optional'])) {
768
                    unset($submission->{$attribute});
769
                }
770
            }
771
        }
772
        return $submission;
773
    }
774
 
775
    /**
776
     * Returns description of method parameters
777
     *
778
     * @return external_function_parameters
779
     * @since Moodle 3.4
780
     */
781
    public static function get_submissions_parameters() {
782
        return new external_function_parameters(
783
            array(
784
                'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
785
                'userid' => new external_value(PARAM_INT, 'Get submissions done by this user. Use 0 or empty for the current user',
786
                                                VALUE_DEFAULT, 0),
787
                'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.
788
                                                   It will return submissions done by users in the given group.',
789
                                                   VALUE_DEFAULT, 0),
790
                'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
791
                'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0),
792
            )
793
        );
794
    }
795
 
796
    /**
797
     * Retrieves all the workshop submissions visible by the current user or the one done by the given user
798
     * (except example submissions).
799
     *
800
     * @param int $workshopid       the workshop instance id
801
     * @param int $userid           get submissions done by this user
802
     * @param int $groupid          (optional) group id, 0 means that the function will determine the user group
803
     * @param int $page             page of records to return
804
     * @param int $perpage          number of records to return per page
805
     * @return array of warnings and the entries
806
     * @since Moodle 3.4
807
     * @throws moodle_exception
808
     */
809
    public static function get_submissions($workshopid, $userid = 0, $groupid = 0, $page = 0, $perpage = 0) {
810
        global $PAGE, $USER;
811
 
812
        $params = array('workshopid' => $workshopid, 'userid' => $userid, 'groupid' => $groupid,
813
            'page' => $page, 'perpage' => $perpage);
814
        $params = self::validate_parameters(self::get_submissions_parameters(), $params);
815
        $submissions = $warnings = array();
816
 
817
        list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
818
 
819
        if (empty($params['groupid'])) {
820
            // Check to see if groups are being used here.
821
            if ($groupmode = groups_get_activity_groupmode($cm)) {
822
                $groupid = groups_get_activity_group($cm);
823
                // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
824
                if (!groups_group_visible($groupid, $course, $cm)) {
825
                    throw new moodle_exception('notingroup');
826
                }
827
            } else {
828
                $groupid = 0;
829
            }
830
        }
831
 
832
        if (!empty($params['userid']) && $params['userid'] != $USER->id) {
833
            $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
834
            core_user::require_active_user($user);
835
            if (!$workshop->check_group_membership($user->id)) {
836
                throw new moodle_exception('notingroup');
837
            }
838
        }
839
 
840
        $totalfilesize = 0;
841
        list($submissionsrecords, $totalcount) =
842
            $workshop->get_visible_submissions($params['userid'], $groupid, $params['page'], $params['perpage']);
843
 
844
        if ($totalcount) {
845
 
846
            $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $context);
847
            $canviewauthornames = has_capability('mod/workshop:viewauthornames', $context);
848
            $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $context);
849
 
850
            $related = array('context' => $context);
851
            foreach ($submissionsrecords as $submission) {
852
                $submission = self::prepare_submission_for_external($submission, $workshop, $canviewauthorpublished,
853
                    $canviewauthornames, $canviewallsubmissions);
854
 
855
                $exporter = new submission_exporter($submission, $related);
856
                $submissions[] = $exporter->export($PAGE->get_renderer('core'));
857
            }
858
 
859
            // Retrieve total files size for the submissions (so external clients know how many data they'd need to download).
860
            $fs = get_file_storage();
861
            $files = $fs->get_area_files($context->id, 'mod_workshop', array('submission_content', 'submission_attachment'));
862
            foreach ($files as $file) {
863
                if ($file->is_directory()) {
864
                    continue;
865
                }
866
                $totalfilesize += $file->get_filesize();
867
            }
868
        }
869
 
870
        return array(
871
            'submissions' => $submissions,
872
            'totalcount' => $totalcount,
873
            'totalfilesize' => $totalfilesize,
874
        );
875
    }
876
 
877
    /**
878
     * Returns description of method result value
879
     *
880
     * @return \core_external\external_description
881
     * @since Moodle 3.4
882
     */
883
    public static function get_submissions_returns() {
884
        return new external_single_structure(
885
            array(
886
                'submissions' => new external_multiple_structure(
887
                    submission_exporter::get_read_structure()
888
                ),
889
                'totalcount' => new external_value(PARAM_INT, 'Total count of submissions.'),
890
                'totalfilesize' => new external_value(PARAM_INT, 'Total size (bytes) of the files attached to all the
891
                    submissions (even the ones not returned due to pagination).'),
892
                'warnings' => new external_warnings()
893
            )
894
        );
895
    }
896
 
897
    /**
898
     * Helper method for validating a submission.
899
     *
900
     * @param  stdClass   $submission submission object
901
     * @param  workshop   $workshop     workshop instance
902
     * @return void
903
     * @since  Moodle 3.4
904
     */
905
    protected static function validate_submission($submission, workshop $workshop) {
906
        global $USER;
907
 
908
        $workshopclosed = $workshop->phase == workshop::PHASE_CLOSED;
909
        $canviewpublished = has_capability('mod/workshop:viewpublishedsubmissions', $workshop->context);
910
 
911
        $canview = $submission->authorid == $USER->id;  // I did it.
912
        $canview = $canview || !empty($workshop->get_assessment_of_submission_by_user($submission->id, $USER->id));  // I reviewed.
913
        $canview = $canview || has_capability('mod/workshop:viewallsubmissions', $workshop->context); // I can view all.
914
        $canview = $canview || ($submission->published && $workshopclosed && $canviewpublished);    // It has been published.
915
 
916
        if ($canview) {
917
            // Here we should check if the user share group.
918
            if ($submission->authorid != $USER->id &&
919
                    !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) {
920
                throw new moodle_exception('notingroup');
921
            }
922
        } else {
923
            throw new moodle_exception('nopermissions', 'error', '', 'view submission');
924
        }
925
    }
926
 
927
    /**
928
     * Returns the description of the external function parameters.
929
     *
930
     * @return external_function_parameters
931
     * @since Moodle 3.4
932
     */
933
    public static function get_submission_parameters() {
934
        return new external_function_parameters(
935
            array(
936
                'submissionid' => new external_value(PARAM_INT, 'Submission id'),
937
            )
938
        );
939
    }
940
 
941
 
942
    /**
943
     * Retrieves the given submission.
944
     *
945
     * @param int $submissionid the submission id
946
     * @return array containing the submission and warnings.
947
     * @since Moodle 3.4
948
     * @throws moodle_exception
949
     */
950
    public static function get_submission($submissionid) {
951
        global $USER, $DB, $PAGE;
952
 
953
        $params = self::validate_parameters(self::get_submission_parameters(), array('submissionid' => $submissionid));
954
        $warnings = array();
955
 
956
        // Get and validate the submission and workshop.
957
        $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
958
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
959
 
960
        self::validate_submission($submission, $workshop);
961
 
962
        $submission = self::prepare_submission_for_external($submission, $workshop);
963
 
964
        $related = array('context' => $context);
965
        $exporter = new submission_exporter($submission, $related);
966
        return array(
967
            'submission' => $exporter->export($PAGE->get_renderer('core')),
968
            'warnings' => $warnings
969
        );
970
    }
971
 
972
    /**
973
     * Returns description of method result value
974
     *
975
     * @return \core_external\external_description
976
     * @since Moodle 3.4
977
     */
978
    public static function get_submission_returns() {
979
        return new external_single_structure(
980
            array(
981
                'submission' => submission_exporter::get_read_structure(),
982
                'warnings' => new external_warnings()
983
            )
984
        );
985
    }
986
 
987
    /**
988
     * Helper method for validating if the current user can view the submission assessments.
989
     *
990
     * @param  stdClass   $submission submission object
991
     * @param  workshop   $workshop     workshop instance
992
     * @return void
993
     * @since  Moodle 3.4
994
     */
995
    protected static function check_view_submission_assessments($submission, workshop $workshop) {
996
        global $USER;
997
 
998
        $ownsubmission = $submission->authorid == $USER->id;
999
        $canview = has_capability('mod/workshop:viewallassessments', $workshop->context) ||
1000
            ($ownsubmission && $workshop->assessments_available());
1001
 
1002
        if ($canview) {
1003
            // Here we should check if the user share group.
1004
            if ($submission->authorid != $USER->id &&
1005
                    !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) {
1006
                throw new moodle_exception('notingroup');
1007
            }
1008
        } else {
1009
            throw new moodle_exception('nopermissions', 'error', '', 'view assessment');
1010
        }
1011
    }
1012
 
1013
    /**
1014
     * Helper method for returning the assessment data according the current user capabilities and current phase.
1015
     *
1016
     * @param  stdClass $assessment the assessment data
1017
     * @param  workshop $workshop   the workshop class
1018
     * @return stdClass object with the assessment data filtered or null if is not viewable yet
1019
     * @since Moodle 3.4
1020
     */
1021
    protected static function prepare_assessment_for_external($assessment, workshop $workshop) {
1022
        global $USER;
1023
        static $canviewallassessments = null;
1024
        static $canviewreviewers = null;
1025
        static $canoverridegrades = null;
1026
 
1027
        // Remove all the properties that does not belong to the assessment table.
1028
        $properties = assessment_exporter::properties_definition();
1029
        foreach ($assessment as $key => $value) {
1030
            if (!isset($properties[$key])) {
1031
                unset($assessment->{$key});
1032
            }
1033
        }
1034
 
1035
        if (is_null($canviewallassessments)) {
1036
            $canviewallassessments = has_capability('mod/workshop:viewallassessments', $workshop->context);
1037
        }
1038
        if (is_null($canviewreviewers)) {
1039
            $canviewreviewers = has_capability('mod/workshop:viewreviewernames', $workshop->context);
1040
        }
1041
        if (is_null($canoverridegrades)) {
1042
            $canoverridegrades = has_capability('mod/workshop:overridegrades', $workshop->context);
1043
        }
1044
 
1045
        $isreviewer = $assessment->reviewerid == $USER->id;
1046
 
1047
        if (!$isreviewer && is_null($assessment->grade) && !$canviewallassessments) {
1048
            // Students do not see peer-assessment that are not graded yet.
1049
            return null;
1050
        }
1051
 
1052
        // Remove the feedback for the reviewer if:
1053
        // I can't see it in the evaluation phase because I'm not a teacher or the reviewer AND
1054
        // I can't see it in the assessment phase because I'm not a teacher.
1055
        if (($workshop->phase < workshop::PHASE_EVALUATION || !($isreviewer || $canviewallassessments)) &&
1056
                ($workshop->phase < workshop::PHASE_ASSESSMENT || !$canviewallassessments) ) {
1057
            // Remove all the feedback information (all the optional fields).
1058
            foreach ($properties as $attribute => $settings) {
1059
                if (!empty($settings['optional'])) {
1060
                    unset($assessment->{$attribute});
1061
                }
1062
            }
1063
        }
1064
 
1065
        if (!$isreviewer && !$canviewreviewers) {
1066
            $assessment->reviewerid = 0;
1067
        }
1068
 
1069
        return $assessment;
1070
    }
1071
 
1072
    /**
1073
     * Returns the description of the external function parameters.
1074
     *
1075
     * @return external_function_parameters
1076
     * @since Moodle 3.4
1077
     */
1078
    public static function get_submission_assessments_parameters() {
1079
        return new external_function_parameters(
1080
            array(
1081
                'submissionid' => new external_value(PARAM_INT, 'Submission id'),
1082
            )
1083
        );
1084
    }
1085
 
1086
 
1087
    /**
1088
     * Retrieves the given submission assessments.
1089
     *
1090
     * @param int $submissionid the submission id
1091
     * @return array containing the assessments and warnings.
1092
     * @since Moodle 3.4
1093
     * @throws moodle_exception
1094
     */
1095
    public static function get_submission_assessments($submissionid) {
1096
        global $USER, $DB, $PAGE;
1097
 
1098
        $params = self::validate_parameters(self::get_submission_assessments_parameters(), array('submissionid' => $submissionid));
1099
        $warnings = $assessments = array();
1100
 
1101
        // Get and validate the submission and workshop.
1102
        $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
1103
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1104
 
1105
        // Check that we can get the assessments and get them.
1106
        self::check_view_submission_assessments($submission, $workshop);
1107
        $assessmentsrecords = $workshop->get_assessments_of_submission($submission->id);
1108
 
1109
        $related = array('context' => $context);
1110
        foreach ($assessmentsrecords as $assessment) {
1111
            $assessment = self::prepare_assessment_for_external($assessment, $workshop);
1112
            if (empty($assessment)) {
1113
                continue;
1114
            }
1115
            $exporter = new assessment_exporter($assessment, $related);
1116
            $assessments[] = $exporter->export($PAGE->get_renderer('core'));
1117
        }
1118
 
1119
        return array(
1120
            'assessments' => $assessments,
1121
            'warnings' => $warnings
1122
        );
1123
    }
1124
 
1125
    /**
1126
     * Returns description of method result value
1127
     *
1128
     * @return \core_external\external_description
1129
     * @since Moodle 3.4
1130
     */
1131
    public static function get_submission_assessments_returns() {
1132
        return new external_single_structure(
1133
            array(
1134
                'assessments' => new external_multiple_structure(
1135
                    assessment_exporter::get_read_structure()
1136
                ),
1137
                'warnings' => new external_warnings()
1138
            )
1139
        );
1140
    }
1141
 
1142
    /**
1143
     * Returns the description of the external function parameters.
1144
     *
1145
     * @return external_function_parameters
1146
     * @since Moodle 3.4
1147
     */
1148
    public static function get_assessment_parameters() {
1149
        return new external_function_parameters(
1150
            array(
1151
                'assessmentid' => new external_value(PARAM_INT, 'Assessment id'),
1152
            )
1153
        );
1154
    }
1155
 
1156
 
1157
    /**
1158
     * Retrieves the given assessment.
1159
     *
1160
     * @param int $assessmentid the assessment id
1161
     * @return array containing the assessment and warnings.
1162
     * @since Moodle 3.4
1163
     * @throws moodle_exception
1164
     */
1165
    public static function get_assessment($assessmentid) {
1166
        global $DB, $PAGE;
1167
 
1168
        $params = self::validate_parameters(self::get_assessment_parameters(), array('assessmentid' => $assessmentid));
1169
        $warnings = array();
1170
 
1171
        // Get and validate the assessment, submission and workshop.
1172
        $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
1173
        $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
1174
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1175
 
1176
        // Check that we can get the assessment.
1177
        $workshop->check_view_assessment($assessment, $submission);
1178
 
1179
        $assessment = $workshop->get_assessment_by_id($assessment->id);
1180
        $assessment = self::prepare_assessment_for_external($assessment, $workshop);
1181
        if (empty($assessment)) {
1182
            throw new moodle_exception('nopermissions', 'error', '', 'view assessment');
1183
        }
1184
        $related = array('context' => $context);
1185
        $exporter = new assessment_exporter($assessment, $related);
1186
 
1187
        return array(
1188
            'assessment' => $exporter->export($PAGE->get_renderer('core')),
1189
            'warnings' => $warnings
1190
        );
1191
    }
1192
 
1193
    /**
1194
     * Returns description of method result value
1195
     *
1196
     * @return \core_external\external_description
1197
     * @since Moodle 3.4
1198
     */
1199
    public static function get_assessment_returns() {
1200
        return new external_single_structure(
1201
            array(
1202
                'assessment' => assessment_exporter::get_read_structure(),
1203
                'warnings' => new external_warnings()
1204
            )
1205
        );
1206
    }
1207
 
1208
    /**
1209
     * Returns the description of the external function parameters.
1210
     *
1211
     * @return external_function_parameters
1212
     * @since Moodle 3.4
1213
     */
1214
    public static function get_assessment_form_definition_parameters() {
1215
        return new external_function_parameters(
1216
            array(
1217
                'assessmentid' => new external_value(PARAM_INT, 'Assessment id'),
1218
                'mode' => new external_value(PARAM_ALPHA, 'The form mode (assessment or preview)', VALUE_DEFAULT, 'assessment'),
1219
            )
1220
        );
1221
    }
1222
 
1223
 
1224
    /**
1225
     * Retrieves the assessment form definition (data required to be able to display the assessment form).
1226
     *
1227
     * @param int $assessmentid the assessment id
1228
     * @param string $mode the form mode (assessment or preview)
1229
     * @return array containing the assessment and warnings.
1230
     * @since Moodle 3.4
1231
     * @throws moodle_exception
1232
     */
1233
    public static function get_assessment_form_definition($assessmentid, $mode = 'assessment') {
1234
        global $DB, $USER;
1235
 
1236
        $params = self::validate_parameters(
1237
            self::get_assessment_form_definition_parameters(), array('assessmentid' => $assessmentid, 'mode' => $mode)
1238
        );
1239
        $warnings = $pending = array();
1240
 
1241
        if ($params['mode'] != 'assessment' && $params['mode'] != 'preview') {
1242
            throw new invalid_parameter_exception('Invalid value for mode parameter (value: ' . $params['mode'] . ')');
1243
        }
1244
 
1245
        // Get and validate the assessment, submission and workshop.
1246
        $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
1247
        $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
1248
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1249
 
1250
        // Check we can view the assessment (so we can get the form data).
1251
        $workshop->check_view_assessment($assessment, $submission);
1252
 
1253
        $cansetassessmentweight = has_capability('mod/workshop:allocate', $context);
1254
        $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id);
1255
 
1256
        // Retrieve the data from the strategy plugin.
1257
        $strategy = $workshop->grading_strategy_instance();
1258
        $strategyname = str_replace('_strategy', '', get_class($strategy)); // Get strategy name.
1259
        $mform = $strategy->get_assessment_form(null, $params['mode'], $assessment, true,
1260
            array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending)));
1261
        $formdata = $mform->get_customdata();
1262
 
1263
        $result = array(
1264
            'dimenssionscount' => $formdata['nodims'],
1265
            'descriptionfiles' => util::get_area_files($context->id, $strategyname, 'description'),
1266
            'warnings' => $warnings
1267
        );
1268
        // Include missing dimension fields.
1269
        for ($i = 0; $i < $formdata['nodims']; $i++) {
1270
            $formdata['fields']->{'gradeid__idx_' . $i} = 0;
1271
            $formdata['fields']->{'peercomment__idx_' . $i} = '';
1272
        }
1273
 
1274
        // Convert all the form data for external.
1275
        foreach (array('options', 'fields', 'current') as $typeofdata) {
1276
            $result[$typeofdata] = array();
1277
 
1278
            if (!empty($formdata[$typeofdata])) {
1279
                $alldata = (array) $formdata[$typeofdata];
1280
                foreach ($alldata as $key => $val) {
1281
                    if (strpos($key, 'description__idx_')) {
1282
                        // Format dimension description.
1283
                        $id = str_replace('description__idx_', '', $key);
1284
                        list($val, $format) = \core_external\util::format_text($val, $alldata['dimensionid__idx_' . $id . 'format'],
1285
                            $context->id, $strategyname, 'description', $alldata['dimensionid__idx_' . $id]);
1286
                    }
1287
                    $result[$typeofdata][] = array(
1288
                        'name' => $key,
1289
                        'value' => $val
1290
                    );
1291
                }
1292
            }
1293
        }
1294
 
1295
        // Get dimensions info.
1296
        $grader = $workshop->grading_strategy_instance();
1297
        $result['dimensionsinfo'] = $grader->get_dimensions_info();
1298
 
1299
        return $result;
1300
    }
1301
 
1302
    /**
1303
     * Returns description of method result value
1304
     *
1305
     * @return \core_external\external_description
1306
     * @since Moodle 3.4
1307
     */
1308
    public static function get_assessment_form_definition_returns() {
1309
        return new external_single_structure(
1310
            array(
1311
                'dimenssionscount' => new external_value(PARAM_INT, 'The number of dimenssions used by the form.'),
1312
                'descriptionfiles' => new external_files('Files in the description text'),
1313
                'options' => new external_multiple_structure(
1314
                    new external_single_structure(
1315
                        array(
1316
                            'name' => new external_value(PARAM_ALPHANUMEXT, 'Option name.'),
1317
                            'value' => new external_value(PARAM_NOTAGS, 'Option value.')
1318
                        )
1319
                    ), 'The form options.'
1320
                ),
1321
                'fields' => new external_multiple_structure(
1322
                    new external_single_structure(
1323
                        array(
1324
                            'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'),
1325
                            'value' => new external_value(PARAM_RAW, 'Field default value.')
1326
                        )
1327
                    ), 'The form fields.'
1328
                ),
1329
                'current' => new external_multiple_structure(
1330
                    new external_single_structure(
1331
                        array(
1332
                            'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'),
1333
                            'value' => new external_value(PARAM_RAW, 'Current field value.')
1334
                        )
1335
                    ), 'The current field values.'
1336
                ),
1337
                'dimensionsinfo' => new external_multiple_structure(
1338
                    new external_single_structure(
1339
                        array(
1340
                            'id' => new external_value(PARAM_INT, 'Dimension id.'),
1341
                            'min' => new external_value(PARAM_FLOAT, 'Minimum grade for the dimension.'),
1342
                            'max' => new external_value(PARAM_FLOAT, 'Maximum grade for the dimension.'),
1343
                            'weight' => new external_value(PARAM_TEXT, 'The weight of the dimension.'),
1344
                            'scale' => new external_value(PARAM_TEXT, 'Scale items (if used).', VALUE_OPTIONAL),
1345
                        )
1346
                    ), 'The dimensions general information.'
1347
                ),
1348
                'warnings' => new external_warnings()
1349
            )
1350
        );
1351
    }
1352
 
1353
    /**
1354
     * Returns the description of the external function parameters.
1355
     *
1356
     * @return external_function_parameters
1357
     * @since Moodle 3.4
1358
     */
1359
    public static function get_reviewer_assessments_parameters() {
1360
        return new external_function_parameters(
1361
            array(
1362
                'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
1363
                'userid' => new external_value(PARAM_INT, 'User id who did the assessment review (empty or 0 for current user).',
1364
                    VALUE_DEFAULT, 0),
1365
            )
1366
        );
1367
    }
1368
 
1369
 
1370
    /**
1371
     * Retrieves all the assessments reviewed by the given user.
1372
     *
1373
     * @param int $workshopid   the workshop instance id
1374
     * @param int $userid       the reviewer user id
1375
     * @return array containing the user assessments and warnings.
1376
     * @since Moodle 3.4
1377
     * @throws moodle_exception
1378
     */
1379
    public static function get_reviewer_assessments($workshopid, $userid = 0) {
1380
        global $USER, $DB, $PAGE;
1381
 
1382
        $params = self::validate_parameters(
1383
            self::get_reviewer_assessments_parameters(), array('workshopid' => $workshopid, 'userid' => $userid)
1384
        );
1385
        $warnings = $assessments = array();
1386
 
1387
        // Get and validate the submission and workshop.
1388
        list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
1389
 
1390
        // Extra checks so only users with permissions can view other users assessments.
1391
        if (empty($params['userid']) || $params['userid'] == $USER->id) {
1392
            $userid = $USER->id;
1393
            list($assessed, $notice) = $workshop->check_examples_assessed_before_assessment($userid);
1394
            if (!$assessed) {
1395
                throw new moodle_exception($notice, 'mod_workshop');
1396
            }
1397
            if ($workshop->phase < workshop::PHASE_ASSESSMENT) {    // Can view assessments only in assessment phase onwards.
1398
                throw new moodle_exception('nopermissions', 'error', '', 'view assessments');
1399
            }
1400
        } else {
1401
            require_capability('mod/workshop:viewallassessments', $context);
1402
            $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
1403
            core_user::require_active_user($user);
1404
            if (!$workshop->check_group_membership($user->id)) {
1405
                throw new moodle_exception('notingroup');
1406
            }
1407
            $userid = $user->id;
1408
        }
1409
        // Now get all my assessments (includes those pending review).
1410
        $assessmentsrecords = $workshop->get_assessments_by_reviewer($userid);
1411
 
1412
        $related = array('context' => $context);
1413
        foreach ($assessmentsrecords as $assessment) {
1414
            $assessment = self::prepare_assessment_for_external($assessment, $workshop);
1415
            if (empty($assessment)) {
1416
                continue;
1417
            }
1418
            $exporter = new assessment_exporter($assessment, $related);
1419
            $assessments[] = $exporter->export($PAGE->get_renderer('core'));
1420
        }
1421
 
1422
        return array(
1423
            'assessments' => $assessments,
1424
            'warnings' => $warnings
1425
        );
1426
    }
1427
 
1428
    /**
1429
     * Returns description of method result value
1430
     *
1431
     * @return \core_external\external_description
1432
     * @since Moodle 3.4
1433
     */
1434
    public static function get_reviewer_assessments_returns() {
1435
        return new external_single_structure(
1436
            array(
1437
                'assessments' => new external_multiple_structure(
1438
                    assessment_exporter::get_read_structure()
1439
                ),
1440
                'warnings' => new external_warnings()
1441
            )
1442
        );
1443
    }
1444
 
1445
    /**
1446
     * Returns the description of the external function parameters.
1447
     *
1448
     * @return external_function_parameters
1449
     * @since Moodle 3.4
1450
     */
1451
    public static function update_assessment_parameters() {
1452
        return new external_function_parameters(
1453
            array(
1454
                'assessmentid' => new external_value(PARAM_INT, 'Assessment id.'),
1455
                'data' => new external_multiple_structure (
1456
                    new external_single_structure(
1457
                        array(
1458
                            'name' => new external_value(PARAM_ALPHANUMEXT,
1459
                                'The assessment data (use WS get_assessment_form_definition for obtaining the data to sent).
1460
                                Apart from that data, you can optionally send:
1461
                                feedbackauthor (str); the feedback for the submission author
1462
                                feedbackauthorformat (int); the format of the feedbackauthor
1463
                                feedbackauthorinlineattachmentsid (int); the draft file area for the editor attachments
1464
                                feedbackauthorattachmentsid (int); the draft file area id for the feedback attachments'
1465
                            ),
1466
                            'value' => new external_value(PARAM_RAW, 'The value of the option.')
1467
                        )
1468
                    ), 'Assessment data'
1469
                )
1470
            )
1471
        );
1472
    }
1473
 
1474
 
1475
    /**
1476
     * Updates an assessment.
1477
     *
1478
     * @param int $assessmentid the assessment id
1479
     * @param array $data the assessment data
1480
     * @return array indicates if the assessment was updated, the new raw grade and possible warnings.
1481
     * @since Moodle 3.4
1482
     * @throws moodle_exception
1483
     */
1484
    public static function update_assessment($assessmentid, $data) {
1485
        global $DB, $USER;
1486
 
1487
        $params = self::validate_parameters(
1488
            self::update_assessment_parameters(), array('assessmentid' => $assessmentid, 'data' => $data)
1489
        );
1490
        $warnings = array();
1491
 
1492
        // Get and validate the assessment, submission and workshop.
1493
        $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
1494
        $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
1495
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1496
 
1497
        // Check we can edit the assessment.
1498
        $workshop->check_edit_assessment($assessment, $submission);
1499
 
1500
        // Process data.
1501
        $data = new stdClass;
1502
        $data->feedbackauthor_editor = array();
1503
 
1504
        foreach ($params['data'] as $wsdata) {
1505
            $name = trim($wsdata['name']);
1506
            switch ($name) {
1507
                case 'feedbackauthor':
1508
                    $data->feedbackauthor_editor['text'] = $wsdata['value'];
1509
                    break;
1510
                case 'feedbackauthorformat':
1511
                    $data->feedbackauthor_editor['format'] = clean_param($wsdata['value'], PARAM_ALPHANUMEXT);
1512
                    break;
1513
                case 'feedbackauthorinlineattachmentsid':
1514
                    $data->feedbackauthor_editor['itemid'] = clean_param($wsdata['value'], PARAM_INT);
1515
                    break;
1516
                case 'feedbackauthorattachmentsid':
1517
                    $data->feedbackauthorattachment_filemanager = clean_param($wsdata['value'], PARAM_INT);
1518
                    break;
1519
                default:
1520
                    $data->{$wsdata['name']} = $wsdata['value'];    // Validation will be done in the form->validation.
1521
            }
1522
        }
1523
 
1524
        $cansetassessmentweight = has_capability('mod/workshop:allocate', $context);
1525
        $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id);
1526
        // Retrieve the data from the strategy plugin.
1527
        $strategy = $workshop->grading_strategy_instance();
1528
        $mform = $strategy->get_assessment_form(null, 'assessment', $assessment, true,
1529
            array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending)));
1530
 
1531
        $errors = $mform->validation((array) $data, array());
1532
        // We can get several errors, return them in warnings.
1533
        if (!empty($errors)) {
1534
            $status = false;
1535
            $rawgrade = null;
1536
            foreach ($errors as $itemname => $message) {
1537
                $warnings[] = array(
1538
                    'item' => $itemname,
1539
                    'itemid' => 0,
1540
                    'warningcode' => 'fielderror',
1541
                    'message' => s($message)
1542
                );
1543
            }
1544
        } else {
1545
            $rawgrade = $workshop->edit_assessment($assessment, $submission, $data, $strategy);
1546
            $status = true;
1547
        }
1548
 
1549
        return array(
1550
            'status' => $status,
1551
            'rawgrade' => $rawgrade,
1552
            'warnings' => $warnings,
1553
        );
1554
    }
1555
 
1556
    /**
1557
     * Returns description of method result value
1558
     *
1559
     * @return \core_external\external_description
1560
     * @since Moodle 3.4
1561
     */
1562
    public static function update_assessment_returns() {
1563
        return new external_single_structure(
1564
            array(
1565
                'status' => new external_value(PARAM_BOOL, 'status: true if the assessment was added or updated false otherwise.'),
1566
                'rawgrade' => new external_value(PARAM_FLOAT, 'Raw percentual grade (0.00000 to 100.00000) for submission.',
1567
                    VALUE_OPTIONAL),
1568
                'warnings' => new external_warnings()
1569
            )
1570
        );
1571
    }
1572
 
1573
    /**
1574
     * Returns the description of the external function parameters.
1575
     *
1576
     * @return external_external_function_parameters
1577
     * @since Moodle 3.4
1578
     */
1579
    public static function get_grades_parameters() {
1580
        return new external_function_parameters (
1581
            array(
1582
                'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
1583
                'userid' => new external_value(PARAM_INT, 'User id (empty or 0 for current user).', VALUE_DEFAULT, 0),
1584
            )
1585
        );
1586
    }
1587
 
1588
    /**
1589
     * Returns the grades information for the given workshop and user.
1590
     *
1591
     * @param int $workshopid workshop instance id
1592
     * @param int $userid user id
1593
     * @return array of warnings and the user plan
1594
     * @since Moodle 3.4
1595
     * @throws  moodle_exception
1596
     */
1597
    public static function get_grades($workshopid, $userid = 0) {
1598
        global $USER;
1599
 
1600
        $params = array(
1601
            'workshopid' => $workshopid,
1602
            'userid' => $userid,
1603
        );
1604
        $params = self::validate_parameters(self::get_grades_parameters(), $params);
1605
        $warnings = array();
1606
 
1607
        list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
1608
 
1609
        // Extra checks so only users with permissions can view other users plans.
1610
        if (empty($params['userid']) || $params['userid'] == $USER->id) {
1611
            $userid = $USER->id;
1612
        } else {
1613
            require_capability('mod/workshop:viewallassessments', $context);
1614
            $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
1615
            core_user::require_active_user($user);
1616
            if (!$workshop->check_group_membership($user->id)) {
1617
                throw new moodle_exception('notingroup');
1618
            }
1619
            $userid = $user->id;
1620
        }
1621
 
1622
        $finalgrades = $workshop->get_gradebook_grades($userid);
1623
 
1624
        $result = array('warnings' => $warnings);
1625
        if ($finalgrades !== false) {
1626
            if (!empty($finalgrades->submissiongrade)) {
1627
                if (is_numeric($finalgrades->submissiongrade->grade)) {
1628
                    $result['submissionrawgrade'] = $finalgrades->submissiongrade->grade;
1629
                }
1630
                $result['submissionlongstrgrade'] = $finalgrades->submissiongrade->str_long_grade;
1631
                $result['submissiongradehidden'] = $finalgrades->submissiongrade->hidden;
1632
            }
1633
            if (!empty($finalgrades->assessmentgrade)) {
1634
                if (is_numeric($finalgrades->assessmentgrade->grade)) {
1635
                    $result['assessmentrawgrade'] = $finalgrades->assessmentgrade->grade;
1636
                }
1637
                $result['assessmentlongstrgrade'] = $finalgrades->assessmentgrade->str_long_grade;
1638
                $result['assessmentgradehidden'] = $finalgrades->assessmentgrade->hidden;
1639
            }
1640
        }
1641
 
1642
        return $result;
1643
    }
1644
 
1645
    /**
1646
     * Returns description of method result value.
1647
     *
1648
     * @return external_single_structure
1649
     * @since Moodle 3.4
1650
     */
1651
    public static function get_grades_returns() {
1652
        return new external_single_structure(
1653
            array(
1654
                'assessmentrawgrade' => new external_value(PARAM_FLOAT, 'The assessment raw (numeric) grade.', VALUE_OPTIONAL),
1655
                'assessmentlongstrgrade' => new external_value(PARAM_NOTAGS, 'The assessment string grade.', VALUE_OPTIONAL),
1656
                'assessmentgradehidden' => new external_value(PARAM_BOOL, 'Whether the grade is hidden or not.', VALUE_OPTIONAL),
1657
                'submissionrawgrade' => new external_value(PARAM_FLOAT, 'The submission raw (numeric) grade.', VALUE_OPTIONAL),
1658
                'submissionlongstrgrade' => new external_value(PARAM_NOTAGS, 'The submission string grade.', VALUE_OPTIONAL),
1659
                'submissiongradehidden' => new external_value(PARAM_BOOL, 'Whether the grade is hidden or not.', VALUE_OPTIONAL),
1660
                'warnings' => new external_warnings(),
1661
            )
1662
        );
1663
    }
1664
 
1665
    /**
1666
     * Returns the description of the external function parameters.
1667
     *
1668
     * @return external_function_parameters
1669
     * @since Moodle 3.4
1670
     */
1671
    public static function evaluate_assessment_parameters() {
1672
        return new external_function_parameters(
1673
            array(
1674
                'assessmentid' => new external_value(PARAM_INT, 'Assessment id.'),
1675
                'feedbacktext' => new external_value(PARAM_RAW, 'The feedback for the reviewer.', VALUE_DEFAULT, ''),
1676
                'feedbackformat' => new external_value(PARAM_INT, 'The feedback format for text.', VALUE_DEFAULT, FORMAT_MOODLE),
1677
                'weight' => new external_value(PARAM_INT, 'The new weight for the assessment.', VALUE_DEFAULT, 1),
1678
                'gradinggradeover' => new external_value(PARAM_ALPHANUMEXT, 'The new grading grade.', VALUE_DEFAULT, ''),
1679
            )
1680
        );
1681
    }
1682
 
1683
 
1684
    /**
1685
     * Evaluates an assessment (used by teachers for provide feedback to the reviewer).
1686
     *
1687
     * @param int $assessmentid the assessment id
1688
     * @param str $feedbacktext the feedback for the reviewer
1689
     * @param int $feedbackformat the feedback format for the reviewer text
1690
     * @param int $weight the new weight for the assessment
1691
     * @param mixed $gradinggradeover the new grading grade (empty for no overriding the grade)
1692
     * @return array containing the status and warnings.
1693
     * @since Moodle 3.4
1694
     * @throws moodle_exception
1695
     */
1696
    public static function evaluate_assessment($assessmentid, $feedbacktext = '', $feedbackformat = FORMAT_MOODLE, $weight = 1,
1697
            $gradinggradeover = '') {
1698
        global $DB;
1699
 
1700
        $params = self::validate_parameters(
1701
            self::evaluate_assessment_parameters(),
1702
            array(
1703
                'assessmentid' => $assessmentid,
1704
                'feedbacktext' => $feedbacktext,
1705
                'feedbackformat' => $feedbackformat,
1706
                'weight' => $weight,
1707
                'gradinggradeover' => $gradinggradeover,
1708
            )
1709
        );
1710
        $warnings = array();
1711
 
1712
        // Get and validate the assessment, submission and workshop.
1713
        $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
1714
        $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
1715
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1716
 
1717
        // Check we can evaluate the assessment.
1718
        $workshop->check_view_assessment($assessment, $submission);
1719
        $cansetassessmentweight = has_capability('mod/workshop:allocate', $context);
1720
        $canoverridegrades      = has_capability('mod/workshop:overridegrades', $context);
1721
        if (!$canoverridegrades && !$cansetassessmentweight) {
1722
            throw new moodle_exception('nopermissions', 'error', '', 'evaluate assessments');
1723
        }
1724
 
1725
        // Process data.
1726
        $data = new stdClass;
1727
        $data->asid = $assessment->id;
1728
        $data->feedbackreviewer_editor = array(
1729
            'text' => $params['feedbacktext'],
1730
            'format' => $params['feedbackformat'],
1731
        );
1732
        $data->weight = $params['weight'];
1733
        $data->gradinggradeover = $params['gradinggradeover'];
1734
 
1735
        $options = array(
1736
            'editable' => true,
1737
            'editableweight' => $cansetassessmentweight,
1738
            'overridablegradinggrade' => $canoverridegrades
1739
        );
1740
        $feedbackform = $workshop->get_feedbackreviewer_form(null, $assessment, $options);
1741
 
1742
        $errors = $feedbackform->validation((array) $data, array());
1743
        // Extra checks for the new grade and weight.
1744
        $possibleweights = workshop::available_assessment_weights_list();
1745
        if ($data->weight < 0 || $data->weight > max(array_keys($possibleweights))) {
1746
            $errors['weight'] = 'The new weight must be higher or equal to 0 and cannot be higher than the maximum weight for
1747
                assessment.';
1748
        }
1749
        if (is_numeric($data->gradinggradeover) &&
1750
                ($data->gradinggradeover < 0 || $data->gradinggradeover > $workshop->gradinggrade)) {
1751
            $errors['gradinggradeover'] = 'The new grade must be higher or equal to 0 and cannot be higher than the maximum grade
1752
                for assessment.';
1753
        }
1754
 
1755
        // We can get several errors, return them in warnings.
1756
        if (!empty($errors)) {
1757
            $status = false;
1758
            foreach ($errors as $itemname => $message) {
1759
                $warnings[] = array(
1760
                    'item' => $itemname,
1761
                    'itemid' => 0,
1762
                    'warningcode' => 'fielderror',
1763
                    'message' => s($message)
1764
                );
1765
            }
1766
        } else {
1767
            $workshop->evaluate_assessment($assessment, $data, $cansetassessmentweight, $canoverridegrades);
1768
            $status = true;
1769
        }
1770
 
1771
        return array(
1772
            'status' => $status,
1773
            'warnings' => $warnings,
1774
        );
1775
    }
1776
 
1777
    /**
1778
     * Returns description of method result value
1779
     *
1780
     * @return \core_external\external_description
1781
     * @since Moodle 3.4
1782
     */
1783
    public static function evaluate_assessment_returns() {
1784
        return new external_single_structure(
1785
            array(
1786
                'status' => new external_value(PARAM_BOOL, 'status: true if the assessment was evaluated, false otherwise.'),
1787
                'warnings' => new external_warnings()
1788
            )
1789
        );
1790
    }
1791
 
1792
    /**
1793
     * Returns description of method parameters
1794
     *
1795
     * @return external_function_parameters
1796
     * @since Moodle 3.4
1797
     */
1798
    public static function get_grades_report_parameters() {
1799
        return new external_function_parameters(
1800
            array(
1801
                'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
1802
                'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.',
1803
                                                   VALUE_DEFAULT, 0),
1804
                'sortby' => new external_value(PARAM_ALPHA, 'sort by this element: lastname, firstname, submissiontitle,
1805
                    submissionmodified, submissiongrade, gradinggrade.', VALUE_DEFAULT, 'lastname'),
1806
                'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'ASC'),
1807
                'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
1808
                'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0),
1809
            )
1810
        );
1811
    }
1812
 
1813
    /**
1814
     * Retrieves the assessment grades report.
1815
     *
1816
     * @param int $workshopid       the workshop instance id
1817
     * @param int $groupid          (optional) group id, 0 means that the function will determine the user group
1818
     * @param string $sortby        sort by this element
1819
     * @param string $sortdirection sort direction: ASC or DESC
1820
     * @param int $page             page of records to return
1821
     * @param int $perpage          number of records to return per page
1822
     * @return array of warnings and the report data
1823
     * @since Moodle 3.4
1824
     * @throws moodle_exception
1825
     */
1826
    public static function get_grades_report($workshopid, $groupid = 0, $sortby = 'lastname', $sortdirection = 'ASC',
1827
            $page = 0, $perpage = 0) {
1828
        global $USER;
1829
 
1830
        $params = array('workshopid' => $workshopid, 'groupid' => $groupid, 'sortby' => $sortby, 'sortdirection' => $sortdirection,
1831
            'page' => $page, 'perpage' => $perpage);
1832
        $params = self::validate_parameters(self::get_grades_report_parameters(), $params);
1833
        $submissions = $warnings = array();
1834
 
1835
        $sortallowedvalues = array('lastname', 'firstname', 'submissiontitle', 'submissionmodified', 'submissiongrade',
1836
            'gradinggrade');
1837
        if (!in_array($params['sortby'], $sortallowedvalues)) {
1838
            throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' .
1839
                'allowed values are: ' . implode(',', $sortallowedvalues));
1840
        }
1841
 
1842
        $sortdirection = strtoupper($params['sortdirection']);
1843
        $directionallowedvalues = array('ASC', 'DESC');
1844
        if (!in_array($sortdirection, $directionallowedvalues)) {
1845
            throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' .
1846
                'allowed values are: ' . implode(',', $directionallowedvalues));
1847
        }
1848
 
1849
        list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
1850
        require_capability('mod/workshop:viewallassessments', $context);
1851
 
1852
        if (!empty($params['groupid'])) {
1853
            $groupid = $params['groupid'];
1854
            // Determine is the group is visible to user.
1855
            if (!groups_group_visible($groupid, $course, $cm)) {
1856
                throw new moodle_exception('notingroup');
1857
            }
1858
        } else {
1859
            // Check to see if groups are being used here.
1860
            if ($groupmode = groups_get_activity_groupmode($cm)) {
1861
                $groupid = groups_get_activity_group($cm);
1862
                // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
1863
                if (!groups_group_visible($groupid, $course, $cm)) {
1864
                    throw new moodle_exception('notingroup');
1865
                }
1866
            } else {
1867
                $groupid = 0;
1868
            }
1869
        }
1870
 
1871
        if ($workshop->phase >= workshop::PHASE_SUBMISSION) {
1872
            $showauthornames = has_capability('mod/workshop:viewauthornames', $context);
1873
            $showreviewernames = has_capability('mod/workshop:viewreviewernames', $context);
1874
 
1875
            if ($workshop->phase >= workshop::PHASE_EVALUATION) {
1876
                $showsubmissiongrade = true;
1877
                $showgradinggrade = true;
1878
            } else {
1879
                $showsubmissiongrade = false;
1880
                $showgradinggrade = false;
1881
            }
1882
 
1883
            $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $params['page'], $params['perpage'],
1884
                $params['sortby'], $sortdirection);
1885
 
1886
            if (!empty($data)) {
1887
                // Populate the display options for the submissions report.
1888
                $reportopts                      = new stdclass();
1889
                $reportopts->showauthornames     = $showauthornames;
1890
                $reportopts->showreviewernames   = $showreviewernames;
1891
                $reportopts->sortby              = $params['sortby'];
1892
                $reportopts->sorthow             = $sortdirection;
1893
                $reportopts->showsubmissiongrade = $showsubmissiongrade;
1894
                $reportopts->showgradinggrade    = $showgradinggrade;
1895
                $reportopts->workshopphase       = $workshop->phase;
1896
 
1897
                $report = new workshop_grading_report($data, $reportopts);
1898
                return array(
1899
                    'report' => $report->export_data_for_external(),
1900
                    'warnings' => array(),
1901
                );
1902
            }
1903
        }
1904
        throw new moodle_exception('nothingfound', 'workshop');
1905
    }
1906
 
1907
    /**
1908
     * Returns description of method result value
1909
     *
1910
     * @return \core_external\external_description
1911
     * @since Moodle 3.4
1912
     */
1913
    public static function get_grades_report_returns() {
1914
 
1915
        $reviewstructure = new external_single_structure(
1916
            array(
1917
                'userid' => new external_value(PARAM_INT, 'The id of the user (0 when is configured to do not display names).'),
1918
                'assessmentid' => new external_value(PARAM_INT, 'The id of the assessment.'),
1919
                'submissionid' => new external_value(PARAM_INT, 'The id of the submission assessed.'),
1920
                'grade' => new external_value(PARAM_FLOAT, 'The grade for submission.'),
1921
                'gradinggrade' => new external_value(PARAM_FLOAT, 'The grade for assessment.'),
1922
                'gradinggradeover' => new external_value(PARAM_FLOAT, 'The aggregated grade overrided.'),
1923
                'weight' => new external_value(PARAM_INT, 'The weight of the assessment for aggregation.'),
1924
            )
1925
        );
1926
 
1927
        return new external_single_structure(
1928
            array(
1929
                'report' => new external_single_structure(
1930
                    array(
1931
                        'grades' => new external_multiple_structure(
1932
                            new external_single_structure(
1933
                                array(
1934
                                    'userid' => new external_value(PARAM_INT, 'The id of the user being displayed in the report.'),
1935
                                    'submissionid' => new external_value(PARAM_INT, 'Submission id.'),
1936
                                    'submissiontitle' => new external_value(PARAM_RAW, 'Submission title.'),
1937
                                    'submissionmodified' => new external_value(PARAM_INT, 'Timestamp submission was updated.'),
1938
                                    'submissiongrade' => new external_value(PARAM_FLOAT, 'Aggregated grade for the submission.',
1939
                                        VALUE_OPTIONAL),
1940
                                    'gradinggrade' => new external_value(PARAM_FLOAT, 'Computed grade for the assessment.',
1941
                                        VALUE_OPTIONAL),
1942
                                    'submissiongradeover' => new external_value(PARAM_FLOAT, 'Grade for the assessment overrided
1943
                                        by the teacher.', VALUE_OPTIONAL),
1944
                                    'submissiongradeoverby' => new external_value(PARAM_INT, 'The id of the user who overrided
1945
                                        the grade.', VALUE_OPTIONAL),
1946
                                    'submissionpublished' => new external_value(PARAM_INT, 'Whether is a submission published.',
1947
                                        VALUE_OPTIONAL),
1948
                                    'reviewedby' => new external_multiple_structure($reviewstructure, 'The users who reviewed the
1949
                                        user submission.', VALUE_OPTIONAL),
1950
                                    'reviewerof' => new external_multiple_structure($reviewstructure, 'The assessments the user
1951
                                        reviewed.', VALUE_OPTIONAL),
1952
                                )
1953
                            )
1954
                        ),
1955
                        'totalcount' => new external_value(PARAM_INT, 'Number of total submissions.'),
1956
                    )
1957
                ),
1958
                'warnings' => new external_warnings()
1959
            )
1960
        );
1961
    }
1962
 
1963
    /**
1964
     * Describes the parameters for view_submission.
1965
     *
1966
     * @return external_function_parameters
1967
     * @since Moodle 3.4
1968
     */
1969
    public static function view_submission_parameters() {
1970
        return new external_function_parameters (
1971
            array(
1972
                'submissionid' => new external_value(PARAM_INT, 'Submission id'),
1973
            )
1974
        );
1975
    }
1976
 
1977
    /**
1978
     * Trigger the submission viewed event.
1979
     *
1980
     * @param int $submissionid submission id
1981
     * @return array of warnings and status result
1982
     * @since Moodle 3.4
1983
     * @throws moodle_exception
1984
     */
1985
    public static function view_submission($submissionid) {
1986
        global $DB;
1987
 
1988
        $params = self::validate_parameters(self::view_submission_parameters(), array('submissionid' => $submissionid));
1989
        $warnings = array();
1990
 
1991
        // Get and validate the submission and workshop.
1992
        $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
1993
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1994
 
1995
        self::validate_submission($submission, $workshop);
1996
 
1997
        $workshop->set_submission_viewed($submission);
1998
 
1999
        $result = array(
2000
            'status' => true,
2001
            'warnings' => $warnings,
2002
        );
2003
        return $result;
2004
    }
2005
 
2006
    /**
2007
     * Describes the view_submission return value.
2008
     *
2009
     * @return external_single_structure
2010
     * @since Moodle 3.4
2011
     */
2012
    public static function view_submission_returns() {
2013
        return new external_single_structure(
2014
            array(
2015
                'status' => new external_value(PARAM_BOOL, 'status: true if success'),
2016
                'warnings' => new external_warnings(),
2017
            )
2018
        );
2019
    }
2020
 
2021
    /**
2022
     * Returns the description of the external function parameters.
2023
     *
2024
     * @return external_function_parameters
2025
     * @since Moodle 3.4
2026
     */
2027
    public static function evaluate_submission_parameters() {
2028
        return new external_function_parameters(
2029
            array(
2030
                'submissionid' => new external_value(PARAM_INT, 'submission id.'),
2031
                'feedbacktext' => new external_value(PARAM_RAW, 'The feedback for the author.', VALUE_DEFAULT, ''),
2032
                'feedbackformat' => new external_value(PARAM_INT, 'The feedback format for text.', VALUE_DEFAULT, FORMAT_MOODLE),
2033
                'published' => new external_value(PARAM_BOOL, 'Publish the submission for others?.', VALUE_DEFAULT, false),
2034
                'gradeover' => new external_value(PARAM_ALPHANUMEXT, 'The new submission grade.', VALUE_DEFAULT, ''),
2035
            )
2036
        );
2037
    }
2038
 
2039
 
2040
    /**
2041
     * Evaluates a submission (used by teachers for provide feedback or override the submission grade).
2042
     *
2043
     * @param int $submissionid the submission id
2044
     * @param str $feedbacktext the feedback for the author
2045
     * @param int $feedbackformat the feedback format for the reviewer text
2046
     * @param bool $published whether to publish the submission for other users
2047
     * @param mixed $gradeover the new submission grade (empty for no overriding the grade)
2048
     * @return array containing the status and warnings.
2049
     * @since Moodle 3.4
2050
     * @throws moodle_exception
2051
     */
2052
    public static function evaluate_submission($submissionid, $feedbacktext = '', $feedbackformat = FORMAT_MOODLE, $published = 1,
2053
            $gradeover = '') {
2054
        global $DB;
2055
 
2056
        $params = self::validate_parameters(
2057
            self::evaluate_submission_parameters(),
2058
            array(
2059
                'submissionid' => $submissionid,
2060
                'feedbacktext' => $feedbacktext,
2061
                'feedbackformat' => $feedbackformat,
2062
                'published' => $published,
2063
                'gradeover' => $gradeover,
2064
            )
2065
        );
2066
        $warnings = array();
2067
 
2068
        // Get and validate the submission, submission and workshop.
2069
        $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
2070
        list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
2071
 
2072
        // Check we can evaluate the submission.
2073
        self::validate_submission($submission, $workshop);
2074
        $canpublish  = has_capability('mod/workshop:publishsubmissions', $context);
2075
        $canoverride = ($workshop->phase == workshop::PHASE_EVALUATION &&
2076
            has_capability('mod/workshop:overridegrades', $context));
2077
 
2078
        if (!$canpublish && !$canoverride) {
2079
            throw new moodle_exception('nopermissions', 'error', '', 'evaluate submission');
2080
        }
2081
 
2082
        // Process data.
2083
        $data = new stdClass;
2084
        $data->id = $submission->id;
2085
        $data->feedbackauthor_editor = array(
2086
            'text' => $params['feedbacktext'],
2087
            'format' => $params['feedbackformat'],
2088
        );
2089
        $data->published = $params['published'];
2090
        $data->gradeover = $params['gradeover'];
2091
 
2092
        $options = array(
2093
            'editable' => true,
2094
            'editablepublished' => $canpublish,
2095
            'overridablegrade' => $canoverride
2096
        );
2097
        $feedbackform = $workshop->get_feedbackauthor_form(null, $submission, $options);
2098
 
2099
        $errors = $feedbackform->validation((array) $data, array());
2100
        // Extra checks for the new grade (if set).
2101
        if (is_numeric($data->gradeover) && $data->gradeover > $workshop->grade) {
2102
            $errors['gradeover'] = 'The new grade cannot be higher than the maximum grade for submission.';
2103
        }
2104
 
2105
        // We can get several errors, return them in warnings.
2106
        if (!empty($errors)) {
2107
            $status = false;
2108
            foreach ($errors as $itemname => $message) {
2109
                $warnings[] = array(
2110
                    'item' => $itemname,
2111
                    'itemid' => 0,
2112
                    'warningcode' => 'fielderror',
2113
                    'message' => s($message)
2114
                );
2115
            }
2116
        } else {
2117
            $workshop->evaluate_submission($submission, $data, $canpublish, $canoverride);
2118
            $status = true;
2119
        }
2120
 
2121
        return array(
2122
            'status' => $status,
2123
            'warnings' => $warnings,
2124
        );
2125
    }
2126
 
2127
    /**
2128
     * Returns description of method result value
2129
     *
2130
     * @return \core_external\external_description
2131
     * @since Moodle 3.4
2132
     */
2133
    public static function evaluate_submission_returns() {
2134
        return new external_single_structure(
2135
            array(
2136
                'status' => new external_value(PARAM_BOOL, 'status: true if the submission was evaluated, false otherwise.'),
2137
                'warnings' => new external_warnings()
2138
            )
2139
        );
2140
    }
2141
}