MDL-59246 mod_workshop: New WS get_submission_assessments
[moodle.git] / mod / workshop / classes / external.php
CommitLineData
9f1ab2db
JL
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Workshop external API
19 *
20 * @package mod_workshop
21 * @category external
22 * @copyright 2017 Juan Leyva <juan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 * @since Moodle 3.4
25 */
26
27defined('MOODLE_INTERNAL') || die;
28
29require_once("$CFG->libdir/externallib.php");
977fdfa3 30require_once($CFG->dirroot . '/mod/workshop/locallib.php');
9f1ab2db
JL
31
32use mod_workshop\external\workshop_summary_exporter;
3f08cfc5 33use mod_workshop\external\submission_exporter;
30b54b82 34use mod_workshop\external\assessment_exporter;
9f1ab2db
JL
35
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 */
45class mod_workshop_external extends external_api {
46
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 }
62
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;
73
74 $warnings = array();
75 $returnedworkshops = array();
76
77 $params = array(
78 'courseids' => $courseids,
79 );
80 $params = self::validate_parameters(self::get_workshops_by_courses_parameters(), $params);
81
82 $mycourses = array();
83 if (empty($params['courseids'])) {
84 $mycourses = enrol_get_my_courses();
85 $params['courseids'] = array_keys($mycourses);
86 }
87
88 // Ensure there are courseids to loop through.
89 if (!empty($params['courseids'])) {
90
91 list($courses, $warnings) = external_util::validate_courses($params['courseids'], $mycourses);
92 $output = $PAGE->get_renderer('core');
93
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) {
98
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);
103
104 $exporter = new workshop_summary_exporter($workshop, array('context' => $context));
105 $returnedworkshops[] = $exporter->export($output);
106 }
107 }
108
109 $result = array(
110 'workshops' => $returnedworkshops,
111 'warnings' => $warnings
112 );
113 return $result;
114 }
115
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 }
977fdfa3
JL
132
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;
142
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');
146
147 $context = context_module::instance($cm->id);
148 self::validate_context($context);
149
150 $workshop = new workshop($workshop, $cm, $course);
151
152 return array($workshop, $course, $cm, $context);
153 }
154
155
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 }
169
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;
180
181 $params = self::validate_parameters(self::get_workshop_access_information_parameters(), array('workshopid' => $workshopid));
182
183 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
184
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 }
193
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 }
c2cf2450 202 $result['examplesassessed'] = $workshop->check_examples_assessed($USER->id);
977fdfa3
JL
203
204 $result['warnings'] = array();
205 return $result;
206 }
207
208 /**
209 * Describes the get_workshop_access_information return value.
210 *
211 * @return external_single_structure
212 * @since Moodle 3.4
213 */
214 public static function get_workshop_access_information_returns() {
215
216 $structure = array(
217 'creatingsubmissionallowed' => new external_value(PARAM_BOOL,
218 'Is the given user allowed to create their submission?'),
219 'modifyingsubmissionallowed' => new external_value(PARAM_BOOL,
220 'Is the user allowed to modify his existing submission?'),
221 'assessingallowed' => new external_value(PARAM_BOOL,
222 'Is the user allowed to create/edit his assessments?'),
223 'assessingexamplesallowed' => new external_value(PARAM_BOOL,
224 'Are reviewers allowed to create/edit their assessments of the example submissions?.'),
c2cf2450
JL
225 'examplesassessed' => new external_value(PARAM_BOOL,
226 'Whether the given user has assessed all his required examples (always true if there are no examples to assess).'),
977fdfa3
JL
227 'warnings' => new external_warnings()
228 );
229
230 $capabilities = load_capability_def('mod_workshop');
231 foreach ($capabilities as $capname => $capdata) {
232 // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules.
233 $field = 'can' . str_replace('mod/workshop:', '', $capname);
234 $structure[$field] = new external_value(PARAM_BOOL, 'Whether the user has the capability ' . $capname . ' allowed.');
235 }
236
237 return new external_single_structure($structure);
238 }
cd495029
JL
239
240 /**
241 * Describes the parameters for get_user_plan.
242 *
243 * @return external_external_function_parameters
244 * @since Moodle 3.4
245 */
246 public static function get_user_plan_parameters() {
247 return new external_function_parameters (
248 array(
249 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
250 'userid' => new external_value(PARAM_INT, 'User id (empty or 0 for current user).', VALUE_DEFAULT, 0),
251 )
252 );
253 }
254
255 /**
256 * Return the planner information for the given user.
257 *
258 * @param int $workshopid workshop instance id
259 * @param int $userid user id
260 * @return array of warnings and the user plan
261 * @since Moodle 3.4
262 * @throws moodle_exception
263 */
264 public static function get_user_plan($workshopid, $userid = 0) {
265 global $USER;
266
267 $params = array(
268 'workshopid' => $workshopid,
269 'userid' => $userid,
270 );
271 $params = self::validate_parameters(self::get_user_plan_parameters(), $params);
272
273 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
274
275 // Extra checks so only users with permissions can view other users plans.
276 if (empty($params['userid']) || $params['userid'] == $USER->id) {
277 $userid = $USER->id;
278 } else {
279 require_capability('moodle/course:manageactivities', $context);
280 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
281 core_user::require_active_user($user);
282 if (!$workshop->check_group_membership($user->id)) {
283 throw new moodle_exception('notingroup');
284 }
285 $userid = $user->id;
286 }
287
288 // Get the user plan information ready for external functions.
289 $userplan = new workshop_user_plan($workshop, $userid);
290 $userplan = array('phases' => $userplan->phases, 'examples' => $userplan->get_examples());
291 foreach ($userplan['phases'] as $phasecode => $phase) {
292 $phase->code = $phasecode;
293 $userplan['phases'][$phasecode] = (array) $phase;
294 foreach ($userplan['phases'][$phasecode]['tasks'] as $taskcode => $task) {
295 $task->code = $taskcode;
296 if ($task->link instanceof moodle_url) {
297 $task->link = $task->link->out(false);
298 }
299 $userplan['phases'][$phasecode]['tasks'][$taskcode] = (array) $task;
300 }
301 foreach ($userplan['phases'][$phasecode]['actions'] as $actioncode => $action) {
302 if ($action->url instanceof moodle_url) {
303 $action->url = $action->url->out(false);
304 }
305 $userplan['phases'][$phasecode]['actions'][$actioncode] = (array) $action;
306 }
307 }
308
309 $result['userplan'] = $userplan;
310 $result['warnings'] = array();
311 return $result;
312 }
313
314 /**
315 * Describes the get_user_plan return value.
316 *
317 * @return external_single_structure
318 * @since Moodle 3.4
319 */
320 public static function get_user_plan_returns() {
321 return new external_single_structure(
322 array(
323 'userplan' => new external_single_structure(
324 array(
325 'phases' => new external_multiple_structure(
326 new external_single_structure(
327 array(
328 'code' => new external_value(PARAM_INT, 'Phase code.'),
329 'title' => new external_value(PARAM_NOTAGS, 'Phase title.'),
330 'active' => new external_value(PARAM_BOOL, 'Whether is the active task.'),
331 'tasks' => new external_multiple_structure(
332 new external_single_structure(
333 array(
334 'code' => new external_value(PARAM_ALPHA, 'Task code.'),
335 'title' => new external_value(PARAM_RAW, 'Task title.'),
336 'link' => new external_value(PARAM_URL, 'Link to task.'),
337 'details' => new external_value(PARAM_RAW, 'Task details.', VALUE_OPTIONAL),
338 'completed' => new external_value(PARAM_NOTAGS,
339 'Completion information (maybe empty, maybe a boolean or generic info.'),
340 )
341 )
342 ),
343 'actions' => new external_multiple_structure(
344 new external_single_structure(
345 array(
346 'type' => new external_value(PARAM_ALPHA, 'Action type.', VALUE_OPTIONAL),
347 'label' => new external_value(PARAM_RAW, 'Action label.', VALUE_OPTIONAL),
348 'url' => new external_value(PARAM_URL, 'Link to action.'),
349 'method' => new external_value(PARAM_ALPHA, 'Get or post.', VALUE_OPTIONAL),
350 )
351 )
352 ),
353 )
354 )
355 ),
356 'examples' => new external_multiple_structure(
357 new external_single_structure(
358 array(
359 'id' => new external_value(PARAM_INT, 'Example submission id.'),
360 'title' => new external_value(PARAM_RAW, 'Example submission title.'),
361 'assessmentid' => new external_value(PARAM_INT, 'Example submission assessment id.'),
362 'grade' => new external_value(PARAM_FLOAT, 'The submission grade.'),
363 'gradinggrade' => new external_value(PARAM_FLOAT, 'The assessment grade.'),
364 )
365 )
366 ),
367 )
368 ),
369 'warnings' => new external_warnings(),
370 )
371 );
372 }
291645f7
JL
373
374 /**
375 * Describes the parameters for view_workshop.
376 *
377 * @return external_function_parameters
378 * @since Moodle 3.4
379 */
380 public static function view_workshop_parameters() {
381 return new external_function_parameters (
382 array(
383 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id'),
384 )
385 );
386 }
387
388 /**
389 * Trigger the course module viewed event and update the module completion status.
390 *
391 * @param int $workshopid workshop instance id
392 * @return array of warnings and status result
393 * @since Moodle 3.4
394 * @throws moodle_exception
395 */
396 public static function view_workshop($workshopid) {
397
398 $params = array('workshopid' => $workshopid);
399 $params = self::validate_parameters(self::view_workshop_parameters(), $params);
400 $warnings = array();
401
402 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
403
404 $workshop->set_module_viewed();
405
406 $result = array(
407 'status' => true,
408 'warnings' => $warnings,
409 );
410 return $result;
411 }
412
413 /**
414 * Describes the view_workshop return value.
415 *
416 * @return external_single_structure
417 * @since Moodle 3.4
418 */
419 public static function view_workshop_returns() {
420 return new external_single_structure(
421 array(
422 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
423 'warnings' => new external_warnings(),
424 )
425 );
426 }
c2cf2450
JL
427
428 /**
429 * Returns the description of the external function parameters.
430 *
431 * @return external_function_parameters
432 * @since Moodle 3.4
433 */
434 public static function add_submission_parameters() {
435 return new external_function_parameters(array(
436 'workshopid' => new external_value(PARAM_INT, 'Workshop id'),
437 'title' => new external_value(PARAM_TEXT, 'Submission title'),
438 'content' => new external_value(PARAM_RAW, 'Submission text content', VALUE_DEFAULT, ''),
439 'contentformat' => new external_value(PARAM_INT, 'The format used for the content', VALUE_DEFAULT, FORMAT_MOODLE),
440 'inlineattachmentsid' => new external_value(PARAM_INT, 'The draft file area id for inline attachments in the content',
441 VALUE_DEFAULT, 0),
442 'attachmentsid' => new external_value(PARAM_INT, 'The draft file area id for attachments', VALUE_DEFAULT, 0),
443 ));
444 }
445
446 /**
447 * Add a new submission to a given workshop.
448 *
449 * @param int $workshopid the workshop id
450 * @param string $title the submission title
451 * @param string $content the submission text content
452 * @param int $contentformat the format used for the content
453 * @param int $inlineattachmentsid the draft file area id for inline attachments in the content
454 * @param int $attachmentsid the draft file area id for attachments
455 * @return array Containing the new created submission id and warnings.
456 * @since Moodle 3.4
457 * @throws moodle_exception
458 */
459 public static function add_submission($workshopid, $title, $content = '', $contentformat = FORMAT_MOODLE,
460 $inlineattachmentsid = 0, $attachmentsid = 0) {
461 global $USER;
462
463 $params = self::validate_parameters(self::add_submission_parameters(), array(
464 'workshopid' => $workshopid,
465 'title' => $title,
466 'content' => $content,
467 'contentformat' => $contentformat,
468 'inlineattachmentsid' => $inlineattachmentsid,
469 'attachmentsid' => $attachmentsid,
470 ));
471 $warnings = array();
472
473 // Get and validate the workshop.
474 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
475 require_capability('mod/workshop:submit', $context);
476
477 // Check if we can submit now.
478 $canaddsubmission = $workshop->creating_submission_allowed($USER->id);
479 $canaddsubmission = $canaddsubmission && $workshop->check_examples_assessed($USER->id);
480 if (!$canaddsubmission) {
481 throw new moodle_exception('nopermissions', 'error', '', 'add submission');
482 }
483
484 // Prepare the submission object.
485 $submission = new stdClass;
486 $submission->id = null;
487 $submission->cmid = $cm->id;
488 $submission->example = 0;
489 $submission->title = trim($params['title']);
490 $submission->content_editor = array(
491 'text' => $params['content'],
492 'format' => $params['contentformat'],
493 'itemid' => $params['inlineattachmentsid'],
494 );
495 $submission->attachment_filemanager = $params['attachmentsid'];
496
497 if (empty($submission->title)) {
498 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title');
499 }
500
501 $errors = $workshop->validate_submission_data((array) $submission);
502 // We can get several errors, return them in warnings.
503 if (!empty($errors)) {
504 $submission->id = 0;
505 foreach ($errors as $itemname => $message) {
506 $warnings[] = array(
507 'item' => $itemname,
508 'itemid' => 0,
509 'warningcode' => 'fielderror',
510 'message' => s($message)
511 );
512 }
4834e127
JL
513 return array(
514 'status' => false,
515 'warnings' => $warnings
516 );
c2cf2450
JL
517 } else {
518 $submission->id = $workshop->edit_submission($submission);
4834e127
JL
519 return array(
520 'status' => true,
521 'submissionid' => $submission->id,
522 'warnings' => $warnings
523 );
c2cf2450 524 }
c2cf2450
JL
525 }
526
527 /**
528 * Returns the description of the external function return value.
529 *
530 * @return external_description
531 * @since Moodle 3.4
532 */
533 public static function add_submission_returns() {
534 return new external_single_structure(array(
4834e127
JL
535 'status' => new external_value(PARAM_BOOL, 'True if the submission was created false otherwise.'),
536 'submissionid' => new external_value(PARAM_INT, 'New workshop submission id.', VALUE_OPTIONAL),
c2cf2450
JL
537 'warnings' => new external_warnings()
538 ));
539 }
c1698a37
JL
540
541 /**
542 * Returns the description of the external function parameters.
543 *
544 * @return external_function_parameters
545 * @since Moodle 3.4
546 */
547 public static function update_submission_parameters() {
548 return new external_function_parameters(array(
549 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
550 'title' => new external_value(PARAM_TEXT, 'Submission title'),
551 'content' => new external_value(PARAM_RAW, 'Submission text content', VALUE_DEFAULT, ''),
552 'contentformat' => new external_value(PARAM_INT, 'The format used for the content', VALUE_DEFAULT, FORMAT_MOODLE),
553 'inlineattachmentsid' => new external_value(PARAM_INT, 'The draft file area id for inline attachments in the content',
554 VALUE_DEFAULT, 0),
555 'attachmentsid' => new external_value(PARAM_INT, 'The draft file area id for attachments', VALUE_DEFAULT, 0),
556 ));
557 }
558
559
560 /**
561 * Updates the given submission.
562 *
563 * @param int $submissionid the submission id
564 * @param string $title the submission title
565 * @param string $content the submission text content
566 * @param int $contentformat the format used for the content
567 * @param int $inlineattachmentsid the draft file area id for inline attachments in the content
568 * @param int $attachmentsid the draft file area id for attachments
569 * @return array whether the submission was updated and warnings.
570 * @since Moodle 3.4
571 * @throws moodle_exception
572 */
573 public static function update_submission($submissionid, $title, $content = '', $contentformat = FORMAT_MOODLE,
574 $inlineattachmentsid = 0, $attachmentsid = 0) {
575 global $USER, $DB;
576
577 $params = self::validate_parameters(self::update_submission_parameters(), array(
578 'submissionid' => $submissionid,
579 'title' => $title,
580 'content' => $content,
581 'contentformat' => $contentformat,
582 'inlineattachmentsid' => $inlineattachmentsid,
583 'attachmentsid' => $attachmentsid,
584 ));
585 $warnings = array();
586
587 // Get and validate the submission and workshop.
588 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
589 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
590 require_capability('mod/workshop:submit', $context);
591
592 // Check if we can update the submission.
593 $canupdatesubmission = $submission->authorid == $USER->id;
594 $canupdatesubmission = $canupdatesubmission && $workshop->modifying_submission_allowed($USER->id);
595 $canupdatesubmission = $canupdatesubmission && $workshop->check_examples_assessed($USER->id);
596 if (!$canupdatesubmission) {
597 throw new moodle_exception('nopermissions', 'error', '', 'update submission');
598 }
599
600 // Prepare the submission object.
601 $submission->title = trim($params['title']);
602 if (empty($submission->title)) {
603 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title');
604 }
605 $submission->content_editor = array(
606 'text' => $params['content'],
607 'format' => $params['contentformat'],
608 'itemid' => $params['inlineattachmentsid'],
609 );
610 $submission->attachment_filemanager = $params['attachmentsid'];
611
612 $errors = $workshop->validate_submission_data((array) $submission);
613 // We can get several errors, return them in warnings.
614 if (!empty($errors)) {
615 $status = false;
616 foreach ($errors as $itemname => $message) {
617 $warnings[] = array(
618 'item' => $itemname,
619 'itemid' => 0,
620 'warningcode' => 'fielderror',
621 'message' => s($message)
622 );
623 }
624 } else {
625 $status = true;
626 $submission->id = $workshop->edit_submission($submission);
627 }
628
629 return array(
630 'status' => $status,
631 'warnings' => $warnings
632 );
633 }
634
635 /**
636 * Returns the description of the external function return value.
637 *
638 * @return external_description
639 * @since Moodle 3.4
640 */
641 public static function update_submission_returns() {
642 return new external_single_structure(array(
643 'status' => new external_value(PARAM_BOOL, 'True if the submission was updated false otherwise.'),
644 'warnings' => new external_warnings()
645 ));
646 }
bde5631d
JL
647
648 /**
649 * Returns the description of the external function parameters.
650 *
651 * @return external_function_parameters
652 * @since Moodle 3.4
653 */
654 public static function delete_submission_parameters() {
655 return new external_function_parameters(
656 array(
657 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
658 )
659 );
660 }
661
662
663 /**
664 * Deletes the given submission.
665 *
666 * @param int $submissionid the submission id.
667 * @return array containing the result status and warnings.
668 * @since Moodle 3.4
669 * @throws moodle_exception
670 */
671 public static function delete_submission($submissionid) {
672 global $USER, $DB;
673
674 $params = self::validate_parameters(self::delete_submission_parameters(), array('submissionid' => $submissionid));
675 $warnings = array();
676
677 // Get and validate the submission and workshop.
678 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
679 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
680
681 // Check if we can delete the submission.
682 if (!has_capability('mod/workshop:deletesubmissions', $context)) {
683 require_capability('mod/workshop:submit', $context);
684 // We can delete our own submission, on time and not yet assessed.
685 $candeletesubmission = $submission->authorid == $USER->id;
686 $candeletesubmission = $candeletesubmission && $workshop->modifying_submission_allowed($USER->id);
687 $candeletesubmission = $candeletesubmission && count($workshop->get_assessments_of_submission($submission->id)) == 0;
688 if (!$candeletesubmission) {
689 throw new moodle_exception('nopermissions', 'error', '', 'delete submission');
690 }
691 }
692
693 $workshop->delete_submission($submission);
694
695 return array(
696 'status' => true,
697 'warnings' => $warnings
698 );
699 }
700
701 /**
702 * Returns the description of the external function return value.
703 *
704 * @return external_description
705 * @since Moodle 3.4
706 */
707 public static function delete_submission_returns() {
708 return new external_single_structure(array(
709 'status' => new external_value(PARAM_BOOL, 'True if the submission was deleted.'),
710 'warnings' => new external_warnings()
711 ));
712 }
3f08cfc5
JL
713
714 /**
715 * Helper method for returning the submission data according the current user capabilities and current phase.
716 *
717 * @param stdClass $submission the submission data
718 * @param workshop $workshop the workshop class
719 * @param bool $canviewauthorpublished whether the user has the capability mod/workshop:viewauthorpublished on
720 * @param bool $canviewauthornames whether the user has the capability mod/workshop:vviewauthornames on
721 * @param bool $canviewallsubmissions whether the user has the capability mod/workshop:viewallsubmissions on
722 * @return stdClass object with the submission data filtered
723 * @since Moodle 3.4
724 */
725 protected static function prepare_submission_for_external($submission, workshop $workshop, $canviewauthorpublished = null,
726 $canviewauthornames = null, $canviewallsubmissions = null) {
727 global $USER;
728
729 if (is_null($canviewauthorpublished)) {
730 $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $workshop->context);
731 }
732 if (is_null($canviewauthornames)) {
733 $canviewauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context);
734 }
735 if (is_null($canviewallsubmissions)) {
736 $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $workshop->context);
737 }
738
739 $ownsubmission = $submission->authorid == $USER->id;
740 if (!$canviewauthornames && !$ownsubmission) {
741 $submission->authorid = 0;
742 }
743
744 $isworkshopclosed = $workshop->phase == workshop::PHASE_CLOSED;
745 $canviewsubmissiondetail = $ownsubmission || $canviewallsubmissions;
746 // If the workshop is not closed or the user can't see the submission detail: remove grading or feedback information.
747 if (!$isworkshopclosed || !$canviewsubmissiondetail) {
748 $properties = submission_exporter::properties_definition();
749 foreach ($properties as $attribute => $settings) {
750 if (!empty($settings['optional'])) {
751 unset($submission->{$attribute});
752 }
753 }
754 }
755 return $submission;
756 }
757
758 /**
759 * Returns description of method parameters
760 *
761 * @return external_function_parameters
762 * @since Moodle 3.4
763 */
764 public static function get_submissions_parameters() {
765 return new external_function_parameters(
766 array(
767 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
768 'userid' => new external_value(PARAM_INT, 'Get submissions done by this user. Use 0 or empty for the current user',
769 VALUE_DEFAULT, 0),
770 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.
771 It will return submissions done by users in the given group.',
772 VALUE_DEFAULT, 0),
773 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
774 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0),
775 )
776 );
777 }
778
779 /**
780 * Retrieves all the workshop submissions visible by the current user or the one done by the given user.
781 *
782 * @param int $workshopid the workshop instance id
783 * @param int $userid get submissions done by this user
784 * @param int $groupid (optional) group id, 0 means that the function will determine the user group
785 * @param int $page page of records to return
786 * @param int $perpage number of records to return per page
787 * @return array of warnings and the entries
788 * @since Moodle 3.4
789 * @throws moodle_exception
790 */
791 public static function get_submissions($workshopid, $userid = 0, $groupid = 0, $page = 0, $perpage = 0) {
792 global $PAGE, $USER;
793
794 $params = array('workshopid' => $workshopid, 'userid' => $userid, 'groupid' => $groupid,
795 'page' => $page, 'perpage' => $perpage);
796 $params = self::validate_parameters(self::get_submissions_parameters(), $params);
797 $submissions = $warnings = array();
798
799 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
800
801 if (empty($params['groupid'])) {
802 // Check to see if groups are being used here.
803 if ($groupmode = groups_get_activity_groupmode($cm)) {
804 $groupid = groups_get_activity_group($cm);
805 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
806 if (!groups_group_visible($groupid, $course, $cm)) {
807 throw new moodle_exception('notingroup');
808 }
809 } else {
810 $groupid = 0;
811 }
812 }
813
814 if (!empty($params['userid']) && $params['userid'] != $USER->id) {
815 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
816 core_user::require_active_user($user);
817 if (!$workshop->check_group_membership($user->id)) {
818 throw new moodle_exception('notingroup');
819 }
820 }
821
822 $totalfilesize = 0;
823 list($submissionsrecords, $totalcount) =
824 $workshop->get_visible_submissions($params['userid'], $groupid, $params['page'], $params['perpage']);
825
826 if ($totalcount) {
827
828 $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $context);
829 $canviewauthornames = has_capability('mod/workshop:viewauthornames', $context);
830 $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $context);
831
832 $related = array('context' => $context);
833 foreach ($submissionsrecords as $submission) {
834 $submission = self::prepare_submission_for_external($submission, $workshop, $canviewauthorpublished,
835 $canviewauthornames, $canviewallsubmissions);
836
837 $exporter = new submission_exporter($submission, $related);
838 $submissions[] = $exporter->export($PAGE->get_renderer('core'));
839 }
840
841 // Retrieve total files size for the submissions (so external clients know how many data they'd need to download).
842 $fs = get_file_storage();
843 $files = $fs->get_area_files($context->id, 'mod_workshop', array('submission_content', 'submission_attachment'));
844 foreach ($files as $file) {
845 if ($file->is_directory() || !isset($submissionsrecords[$file->get_itemid()])) {
846 continue;
847 }
848 $totalfilesize += $file->get_filesize();
849 }
850 }
851
852 return array(
853 'submissions' => $submissions,
854 'totalcount' => $totalcount,
855 'totalfilesize' => $totalfilesize,
856 );
857 }
858
859 /**
860 * Returns description of method result value
861 *
862 * @return external_description
863 * @since Moodle 3.4
864 */
865 public static function get_submissions_returns() {
866 return new external_single_structure(
867 array(
868 'submissions' => new external_multiple_structure(
869 submission_exporter::get_read_structure()
870 ),
871 'totalcount' => new external_value(PARAM_INT, 'Total count of submissions.'),
872 'totalfilesize' => new external_value(PARAM_INT, 'Total size (bytes) of the files included in the submissions.'),
873 'warnings' => new external_warnings()
874 )
875 );
876 }
6e2f4866 877
30b54b82
JL
878 /**
879 * Helper method for validating a submission.
880 *
881 * @param stdClass $submission submission object
882 * @param workshop $workshop workshop instance
883 * @return void
884 * @since Moodle 3.4
885 */
886 protected static function validate_submission($submission, workshop $workshop) {
887 global $USER;
888
889 $workshopclosed = $workshop->phase == workshop::PHASE_CLOSED;
890 $canviewpublished = has_capability('mod/workshop:viewpublishedsubmissions', $workshop->context);
891
892 $canview = $submission->authorid == $USER->id; // I did it.
893 $canview = $canview || !empty($workshop->get_assessment_of_submission_by_user($submission->id, $USER->id)); // I reviewed.
894 $canview = $canview || has_capability('mod/workshop:viewallsubmissions', $workshop->context); // I can view all.
895 $canview = $canview || ($submission->published && $workshopclosed && $canviewpublished); // It has been published.
896
897 if ($canview) {
898 // Here we should check if the user share group.
899 if ($submission->authorid != $USER->id &&
900 !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) {
901 throw new moodle_exception('notingroup');
902 }
903 } else {
904 throw new moodle_exception('nopermissions', 'error', '', 'view submission');
905 }
906 }
907
6e2f4866
JL
908 /**
909 * Returns the description of the external function parameters.
910 *
911 * @return external_function_parameters
912 * @since Moodle 3.4
913 */
914 public static function get_submission_parameters() {
915 return new external_function_parameters(
916 array(
917 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
918 )
919 );
920 }
921
922
923 /**
924 * Retrieves the given submission.
925 *
926 * @param int $submissionid the submission id
927 * @return array containing the submission and warnings.
928 * @since Moodle 3.4
929 * @throws moodle_exception
930 */
931 public static function get_submission($submissionid) {
932 global $USER, $DB, $PAGE;
933
934 $params = self::validate_parameters(self::get_submission_parameters(), array('submissionid' => $submissionid));
935 $warnings = array();
936
937 // Get and validate the submission and workshop.
938 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
939 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
940
30b54b82 941 self::validate_submission($submission, $workshop);
6e2f4866 942
30b54b82
JL
943 $submission = self::prepare_submission_for_external($submission, $workshop);
944
945 $related = array('context' => $context);
946 $exporter = new submission_exporter($submission, $related);
947 return array(
948 'submission' => $exporter->export($PAGE->get_renderer('core')),
949 'warnings' => $warnings
950 );
951 }
952
953 /**
954 * Returns description of method result value
955 *
956 * @return external_description
957 * @since Moodle 3.4
958 */
959 public static function get_submission_returns() {
960 return new external_single_structure(
961 array(
962 'submission' => submission_exporter::get_read_structure(),
963 'warnings' => new external_warnings()
964 )
965 );
966 }
967
968 /**
969 * Helper method for validating if the current user can view the submission assessments.
970 *
971 * @param stdClass $submission submission object
972 * @param workshop $workshop workshop instance
973 * @return void
974 * @since Moodle 3.4
975 */
976 protected static function check_view_submission_assessments($submission, workshop $workshop) {
977 global $USER;
978
979 $ownsubmission = $submission->authorid == $USER->id;
980 $canview = has_capability('mod/workshop:viewallassessments', $workshop->context) ||
981 ($ownsubmission && $workshop->assessments_available());
6e2f4866
JL
982
983 if ($canview) {
984 // Here we should check if the user share group.
30b54b82
JL
985 if ($submission->authorid != $USER->id &&
986 !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) {
6e2f4866
JL
987 throw new moodle_exception('notingroup');
988 }
989 } else {
30b54b82 990 throw new moodle_exception('nopermissions', 'error', '', 'view assessment');
6e2f4866 991 }
30b54b82 992 }
6e2f4866 993
30b54b82
JL
994 /**
995 * Helper method for returning the assessment data according the current user capabilities and current phase.
996 *
997 * @param stdClass $assessment the assessment data
998 * @param workshop $workshop the workshop class
999 * @return stdClass object with the assessment data filtered or null if is not viewable yet
1000 * @since Moodle 3.4
1001 */
1002 protected static function prepare_assessment_for_external($assessment, workshop $workshop) {
1003 global $USER;
1004 static $canviewallassessments = null;
1005 static $canviewreviewers = null;
1006 static $canoverridegrades = null;
1007
1008 // Remove all the properties that does not belong to the assessment table.
1009 $properties = assessment_exporter::properties_definition();
1010 foreach ($assessment as $key => $value) {
1011 if (!isset($properties[$key])) {
1012 unset($assessment->{$key});
1013 }
1014 }
1015
1016 if (is_null($canviewallassessments)) {
1017 $canviewallassessments = has_capability('mod/workshop:viewallassessments', $workshop->context);
1018 }
1019 if (is_null($canviewreviewers)) {
1020 $canviewreviewers = has_capability('mod/workshop:viewreviewernames', $workshop->context);
1021 }
1022 if (is_null($canoverridegrades)) {
1023 $canoverridegrades = has_capability('mod/workshop:overridegrades', $workshop->context);
1024 }
1025
1026 $isreviewer = $assessment->reviewerid == $USER->id;
1027
1028 if (!$isreviewer && is_null($assessment->grade) && !$canviewallassessments) {
1029 // Students do not see peer-assessment that are not graded yet.
1030 return null;
1031 }
1032
1033 // Remove the feedback for the reviewer if the feedback is not closed or if we don't have enough permissions to see it.
1034 if (!$canoverridegrades && ($workshop->phase != workshop::PHASE_CLOSED || !$isreviewer)) {
1035 // Remove all the feedback information (all the optional fields).
1036 foreach ($properties as $attribute => $settings) {
1037 if (!empty($settings['optional'])) {
1038 unset($assessment->{$attribute});
1039 }
1040 }
1041 }
1042
1043 if (!$isreviewer && !$canviewreviewers) {
1044 $assessment->reviewerid = 0;
1045 }
1046
1047 return $assessment;
1048 }
1049
1050 /**
1051 * Returns the description of the external function parameters.
1052 *
1053 * @return external_function_parameters
1054 * @since Moodle 3.4
1055 */
1056 public static function get_submission_assessments_parameters() {
1057 return new external_function_parameters(
1058 array(
1059 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
1060 )
1061 );
1062 }
1063
1064
1065 /**
1066 * Retrieves the given submission assessments.
1067 *
1068 * @param int $submissionid the submission id
1069 * @return array containing the assessments and warnings.
1070 * @since Moodle 3.4
1071 * @throws moodle_exception
1072 */
1073 public static function get_submission_assessments($submissionid) {
1074 global $USER, $DB, $PAGE;
1075
1076 $params = self::validate_parameters(self::get_submission_assessments_parameters(), array('submissionid' => $submissionid));
1077 $warnings = $assessments = array();
1078
1079 // Get and validate the submission and workshop.
1080 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
1081 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1082
1083 // Check that we can get the assessments and get them.
1084 self::check_view_submission_assessments($submission, $workshop);
1085 $assessmentsrecords = $workshop->get_assessments_of_submission($submission->id);
6e2f4866
JL
1086
1087 $related = array('context' => $context);
30b54b82
JL
1088 foreach ($assessmentsrecords as $assessment) {
1089 $assessment = self::prepare_assessment_for_external($assessment, $workshop);
1090 if (empty($assessment)) {
1091 continue;
1092 }
1093 $exporter = new assessment_exporter($assessment, $related);
1094 $assessments[] = $exporter->export($PAGE->get_renderer('core'));
1095 }
1096
6e2f4866 1097 return array(
30b54b82 1098 'assessments' => $assessments,
6e2f4866
JL
1099 'warnings' => $warnings
1100 );
1101 }
1102
1103 /**
1104 * Returns description of method result value
1105 *
1106 * @return external_description
1107 * @since Moodle 3.4
1108 */
30b54b82 1109 public static function get_submission_assessments_returns() {
6e2f4866
JL
1110 return new external_single_structure(
1111 array(
30b54b82
JL
1112 'assessments' => new external_multiple_structure(
1113 assessment_exporter::get_read_structure()
1114 ),
6e2f4866
JL
1115 'warnings' => new external_warnings()
1116 )
1117 );
1118 }
9f1ab2db 1119}