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