MDL-59248 mod_workshop: New WS get_assessment_form_definition
[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 }
86928d2a
JL
202 $result['examplesassessedbeforesubmission'] = $workshop->check_examples_assessed_before_submission($USER->id);
203 list($result['examplesassessedbeforeassessment'], $code) = $workshop->check_examples_assessed_before_assessment($USER->id);
977fdfa3
JL
204
205 $result['warnings'] = array();
206 return $result;
207 }
208
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() {
216
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?.'),
86928d2a
JL
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).'),
977fdfa3
JL
232 'warnings' => new external_warnings()
233 );
234
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 }
241
242 return new external_single_structure($structure);
243 }
cd495029
JL
244
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 }
259
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;
271
272 $params = array(
273 'workshopid' => $workshopid,
274 'userid' => $userid,
275 );
276 $params = self::validate_parameters(self::get_user_plan_parameters(), $params);
277
278 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
279
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 }
292
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 }
313
314 $result['userplan'] = $userplan;
315 $result['warnings'] = array();
316 return $result;
317 }
318
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 }
291645f7
JL
378
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 }
392
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) {
402
403 $params = array('workshopid' => $workshopid);
404 $params = self::validate_parameters(self::view_workshop_parameters(), $params);
405 $warnings = array();
406
407 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
408
409 $workshop->set_module_viewed();
410
411 $result = array(
412 'status' => true,
413 'warnings' => $warnings,
414 );
415 return $result;
416 }
417
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 }
c2cf2450
JL
432
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 }
450
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;
467
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();
477
478 // Get and validate the workshop.
479 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
480 require_capability('mod/workshop:submit', $context);
481
482 // Check if we can submit now.
483 $canaddsubmission = $workshop->creating_submission_allowed($USER->id);
86928d2a 484 $canaddsubmission = $canaddsubmission && $workshop->check_examples_assessed_before_submission($USER->id);
c2cf2450
JL
485 if (!$canaddsubmission) {
486 throw new moodle_exception('nopermissions', 'error', '', 'add submission');
487 }
488
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'];
501
502 if (empty($submission->title)) {
503 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title');
504 }
505
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 }
4834e127
JL
518 return array(
519 'status' => false,
520 'warnings' => $warnings
521 );
c2cf2450
JL
522 } else {
523 $submission->id = $workshop->edit_submission($submission);
4834e127
JL
524 return array(
525 'status' => true,
526 'submissionid' => $submission->id,
527 'warnings' => $warnings
528 );
c2cf2450 529 }
c2cf2450
JL
530 }
531
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(
4834e127
JL
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),
c2cf2450
JL
542 'warnings' => new external_warnings()
543 ));
544 }
c1698a37
JL
545
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 }
563
564
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;
581
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();
591
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);
596
597 // Check if we can update the submission.
598 $canupdatesubmission = $submission->authorid == $USER->id;
599 $canupdatesubmission = $canupdatesubmission && $workshop->modifying_submission_allowed($USER->id);
86928d2a 600 $canupdatesubmission = $canupdatesubmission && $workshop->check_examples_assessed_before_submission($USER->id);
c1698a37
JL
601 if (!$canupdatesubmission) {
602 throw new moodle_exception('nopermissions', 'error', '', 'update submission');
603 }
604
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'];
616
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 }
633
634 return array(
635 'status' => $status,
636 'warnings' => $warnings
637 );
638 }
639
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 }
bde5631d
JL
652
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 }
666
667
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;
678
679 $params = self::validate_parameters(self::delete_submission_parameters(), array('submissionid' => $submissionid));
680 $warnings = array();
681
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);
685
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 }
697
698 $workshop->delete_submission($submission);
699
700 return array(
701 'status' => true,
702 'warnings' => $warnings
703 );
704 }
705
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 }
3f08cfc5
JL
718
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;
733
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 }
743
744 $ownsubmission = $submission->authorid == $USER->id;
745 if (!$canviewauthornames && !$ownsubmission) {
746 $submission->authorid = 0;
747 }
748
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 }
762
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 }
783
784 /**
785 * Retrieves all the workshop submissions visible by the current user or the one done by the given user.
786 *
787 * @param int $workshopid the workshop instance id
788 * @param int $userid get submissions done by this user
789 * @param int $groupid (optional) group id, 0 means that the function will determine the user group
790 * @param int $page page of records to return
791 * @param int $perpage number of records to return per page
792 * @return array of warnings and the entries
793 * @since Moodle 3.4
794 * @throws moodle_exception
795 */
796 public static function get_submissions($workshopid, $userid = 0, $groupid = 0, $page = 0, $perpage = 0) {
797 global $PAGE, $USER;
798
799 $params = array('workshopid' => $workshopid, 'userid' => $userid, 'groupid' => $groupid,
800 'page' => $page, 'perpage' => $perpage);
801 $params = self::validate_parameters(self::get_submissions_parameters(), $params);
802 $submissions = $warnings = array();
803
804 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
805
806 if (empty($params['groupid'])) {
807 // Check to see if groups are being used here.
808 if ($groupmode = groups_get_activity_groupmode($cm)) {
809 $groupid = groups_get_activity_group($cm);
810 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
811 if (!groups_group_visible($groupid, $course, $cm)) {
812 throw new moodle_exception('notingroup');
813 }
814 } else {
815 $groupid = 0;
816 }
817 }
818
819 if (!empty($params['userid']) && $params['userid'] != $USER->id) {
820 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
821 core_user::require_active_user($user);
822 if (!$workshop->check_group_membership($user->id)) {
823 throw new moodle_exception('notingroup');
824 }
825 }
826
827 $totalfilesize = 0;
828 list($submissionsrecords, $totalcount) =
829 $workshop->get_visible_submissions($params['userid'], $groupid, $params['page'], $params['perpage']);
830
831 if ($totalcount) {
832
833 $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $context);
834 $canviewauthornames = has_capability('mod/workshop:viewauthornames', $context);
835 $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $context);
836
837 $related = array('context' => $context);
838 foreach ($submissionsrecords as $submission) {
839 $submission = self::prepare_submission_for_external($submission, $workshop, $canviewauthorpublished,
840 $canviewauthornames, $canviewallsubmissions);
841
842 $exporter = new submission_exporter($submission, $related);
843 $submissions[] = $exporter->export($PAGE->get_renderer('core'));
844 }
845
846 // Retrieve total files size for the submissions (so external clients know how many data they'd need to download).
847 $fs = get_file_storage();
848 $files = $fs->get_area_files($context->id, 'mod_workshop', array('submission_content', 'submission_attachment'));
849 foreach ($files as $file) {
850 if ($file->is_directory() || !isset($submissionsrecords[$file->get_itemid()])) {
851 continue;
852 }
853 $totalfilesize += $file->get_filesize();
854 }
855 }
856
857 return array(
858 'submissions' => $submissions,
859 'totalcount' => $totalcount,
860 'totalfilesize' => $totalfilesize,
861 );
862 }
863
864 /**
865 * Returns description of method result value
866 *
867 * @return external_description
868 * @since Moodle 3.4
869 */
870 public static function get_submissions_returns() {
871 return new external_single_structure(
872 array(
873 'submissions' => new external_multiple_structure(
874 submission_exporter::get_read_structure()
875 ),
876 'totalcount' => new external_value(PARAM_INT, 'Total count of submissions.'),
877 'totalfilesize' => new external_value(PARAM_INT, 'Total size (bytes) of the files included in the submissions.'),
878 'warnings' => new external_warnings()
879 )
880 );
881 }
6e2f4866 882
30b54b82
JL
883 /**
884 * Helper method for validating a submission.
885 *
886 * @param stdClass $submission submission object
887 * @param workshop $workshop workshop instance
888 * @return void
889 * @since Moodle 3.4
890 */
891 protected static function validate_submission($submission, workshop $workshop) {
892 global $USER;
893
894 $workshopclosed = $workshop->phase == workshop::PHASE_CLOSED;
895 $canviewpublished = has_capability('mod/workshop:viewpublishedsubmissions', $workshop->context);
896
897 $canview = $submission->authorid == $USER->id; // I did it.
898 $canview = $canview || !empty($workshop->get_assessment_of_submission_by_user($submission->id, $USER->id)); // I reviewed.
899 $canview = $canview || has_capability('mod/workshop:viewallsubmissions', $workshop->context); // I can view all.
900 $canview = $canview || ($submission->published && $workshopclosed && $canviewpublished); // It has been published.
901
902 if ($canview) {
903 // Here we should check if the user share group.
904 if ($submission->authorid != $USER->id &&
905 !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) {
906 throw new moodle_exception('notingroup');
907 }
908 } else {
909 throw new moodle_exception('nopermissions', 'error', '', 'view submission');
910 }
911 }
912
6e2f4866
JL
913 /**
914 * Returns the description of the external function parameters.
915 *
916 * @return external_function_parameters
917 * @since Moodle 3.4
918 */
919 public static function get_submission_parameters() {
920 return new external_function_parameters(
921 array(
922 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
923 )
924 );
925 }
926
927
928 /**
929 * Retrieves the given submission.
930 *
931 * @param int $submissionid the submission id
932 * @return array containing the submission and warnings.
933 * @since Moodle 3.4
934 * @throws moodle_exception
935 */
936 public static function get_submission($submissionid) {
937 global $USER, $DB, $PAGE;
938
939 $params = self::validate_parameters(self::get_submission_parameters(), array('submissionid' => $submissionid));
940 $warnings = array();
941
942 // Get and validate the submission and workshop.
943 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
944 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
945
30b54b82 946 self::validate_submission($submission, $workshop);
6e2f4866 947
30b54b82
JL
948 $submission = self::prepare_submission_for_external($submission, $workshop);
949
950 $related = array('context' => $context);
951 $exporter = new submission_exporter($submission, $related);
952 return array(
953 'submission' => $exporter->export($PAGE->get_renderer('core')),
954 'warnings' => $warnings
955 );
956 }
957
958 /**
959 * Returns description of method result value
960 *
961 * @return external_description
962 * @since Moodle 3.4
963 */
964 public static function get_submission_returns() {
965 return new external_single_structure(
966 array(
967 'submission' => submission_exporter::get_read_structure(),
968 'warnings' => new external_warnings()
969 )
970 );
971 }
972
973 /**
974 * Helper method for validating if the current user can view the submission assessments.
975 *
976 * @param stdClass $submission submission object
977 * @param workshop $workshop workshop instance
978 * @return void
979 * @since Moodle 3.4
980 */
981 protected static function check_view_submission_assessments($submission, workshop $workshop) {
982 global $USER;
983
984 $ownsubmission = $submission->authorid == $USER->id;
985 $canview = has_capability('mod/workshop:viewallassessments', $workshop->context) ||
986 ($ownsubmission && $workshop->assessments_available());
6e2f4866
JL
987
988 if ($canview) {
989 // Here we should check if the user share group.
30b54b82
JL
990 if ($submission->authorid != $USER->id &&
991 !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) {
6e2f4866
JL
992 throw new moodle_exception('notingroup');
993 }
994 } else {
30b54b82 995 throw new moodle_exception('nopermissions', 'error', '', 'view assessment');
6e2f4866 996 }
30b54b82 997 }
6e2f4866 998
30b54b82
JL
999 /**
1000 * Helper method for returning the assessment data according the current user capabilities and current phase.
1001 *
1002 * @param stdClass $assessment the assessment data
1003 * @param workshop $workshop the workshop class
1004 * @return stdClass object with the assessment data filtered or null if is not viewable yet
1005 * @since Moodle 3.4
1006 */
1007 protected static function prepare_assessment_for_external($assessment, workshop $workshop) {
1008 global $USER;
1009 static $canviewallassessments = null;
1010 static $canviewreviewers = null;
1011 static $canoverridegrades = null;
1012
1013 // Remove all the properties that does not belong to the assessment table.
1014 $properties = assessment_exporter::properties_definition();
1015 foreach ($assessment as $key => $value) {
1016 if (!isset($properties[$key])) {
1017 unset($assessment->{$key});
1018 }
1019 }
1020
1021 if (is_null($canviewallassessments)) {
1022 $canviewallassessments = has_capability('mod/workshop:viewallassessments', $workshop->context);
1023 }
1024 if (is_null($canviewreviewers)) {
1025 $canviewreviewers = has_capability('mod/workshop:viewreviewernames', $workshop->context);
1026 }
1027 if (is_null($canoverridegrades)) {
1028 $canoverridegrades = has_capability('mod/workshop:overridegrades', $workshop->context);
1029 }
1030
1031 $isreviewer = $assessment->reviewerid == $USER->id;
1032
1033 if (!$isreviewer && is_null($assessment->grade) && !$canviewallassessments) {
1034 // Students do not see peer-assessment that are not graded yet.
1035 return null;
1036 }
1037
1038 // Remove the feedback for the reviewer if the feedback is not closed or if we don't have enough permissions to see it.
1039 if (!$canoverridegrades && ($workshop->phase != workshop::PHASE_CLOSED || !$isreviewer)) {
1040 // Remove all the feedback information (all the optional fields).
1041 foreach ($properties as $attribute => $settings) {
1042 if (!empty($settings['optional'])) {
1043 unset($assessment->{$attribute});
1044 }
1045 }
1046 }
1047
1048 if (!$isreviewer && !$canviewreviewers) {
1049 $assessment->reviewerid = 0;
1050 }
1051
1052 return $assessment;
1053 }
1054
1055 /**
1056 * Returns the description of the external function parameters.
1057 *
1058 * @return external_function_parameters
1059 * @since Moodle 3.4
1060 */
1061 public static function get_submission_assessments_parameters() {
1062 return new external_function_parameters(
1063 array(
1064 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
1065 )
1066 );
1067 }
1068
1069
1070 /**
1071 * Retrieves the given submission assessments.
1072 *
1073 * @param int $submissionid the submission id
1074 * @return array containing the assessments and warnings.
1075 * @since Moodle 3.4
1076 * @throws moodle_exception
1077 */
1078 public static function get_submission_assessments($submissionid) {
1079 global $USER, $DB, $PAGE;
1080
1081 $params = self::validate_parameters(self::get_submission_assessments_parameters(), array('submissionid' => $submissionid));
1082 $warnings = $assessments = array();
1083
1084 // Get and validate the submission and workshop.
1085 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
1086 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1087
1088 // Check that we can get the assessments and get them.
1089 self::check_view_submission_assessments($submission, $workshop);
1090 $assessmentsrecords = $workshop->get_assessments_of_submission($submission->id);
6e2f4866
JL
1091
1092 $related = array('context' => $context);
30b54b82
JL
1093 foreach ($assessmentsrecords as $assessment) {
1094 $assessment = self::prepare_assessment_for_external($assessment, $workshop);
1095 if (empty($assessment)) {
1096 continue;
1097 }
1098 $exporter = new assessment_exporter($assessment, $related);
1099 $assessments[] = $exporter->export($PAGE->get_renderer('core'));
1100 }
1101
6e2f4866 1102 return array(
30b54b82 1103 'assessments' => $assessments,
6e2f4866
JL
1104 'warnings' => $warnings
1105 );
1106 }
1107
1108 /**
1109 * Returns description of method result value
1110 *
1111 * @return external_description
1112 * @since Moodle 3.4
1113 */
30b54b82 1114 public static function get_submission_assessments_returns() {
6e2f4866
JL
1115 return new external_single_structure(
1116 array(
30b54b82
JL
1117 'assessments' => new external_multiple_structure(
1118 assessment_exporter::get_read_structure()
1119 ),
6e2f4866
JL
1120 'warnings' => new external_warnings()
1121 )
1122 );
1123 }
b1e896cf
JL
1124
1125 /**
1126 * Returns the description of the external function parameters.
1127 *
1128 * @return external_function_parameters
1129 * @since Moodle 3.4
1130 */
1131 public static function get_assessment_parameters() {
1132 return new external_function_parameters(
1133 array(
1134 'assessmentid' => new external_value(PARAM_INT, 'Assessment id'),
1135 )
1136 );
1137 }
1138
1139
1140 /**
1141 * Retrieves the given assessment.
1142 *
1143 * @param int $assessmentid the assessment id
1144 * @return array containing the assessment and warnings.
1145 * @since Moodle 3.4
1146 * @throws moodle_exception
1147 */
1148 public static function get_assessment($assessmentid) {
1149 global $DB, $PAGE;
1150
1151 $params = self::validate_parameters(self::get_assessment_parameters(), array('assessmentid' => $assessmentid));
1152 $warnings = array();
1153
1154 // Get and validate the assessment, submission and workshop.
1155 $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
1156 $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
1157 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1158
1159 // Check that we can get the assessment.
1160 $workshop->check_view_assessment($assessment, $submission);
1161
1162 $assessment = $workshop->get_assessment_by_id($assessment->id);
1163 $assessment = self::prepare_assessment_for_external($assessment, $workshop);
1164 if (empty($assessment)) {
1165 throw new moodle_exception('nopermissions', 'error', '', 'view assessment');
1166 }
1167 $related = array('context' => $context);
1168 $exporter = new assessment_exporter($assessment, $related);
1169
1170 return array(
1171 'assessment' => $exporter->export($PAGE->get_renderer('core')),
1172 'warnings' => $warnings
1173 );
1174 }
1175
1176 /**
1177 * Returns description of method result value
1178 *
1179 * @return external_description
1180 * @since Moodle 3.4
1181 */
1182 public static function get_assessment_returns() {
1183 return new external_single_structure(
1184 array(
1185 'assessment' => assessment_exporter::get_read_structure(),
1186 'warnings' => new external_warnings()
1187 )
1188 );
1189 }
46f5e9a0
JL
1190
1191 /**
1192 * Returns the description of the external function parameters.
1193 *
1194 * @return external_function_parameters
1195 * @since Moodle 3.4
1196 */
1197 public static function get_assessment_form_definition_parameters() {
1198 return new external_function_parameters(
1199 array(
1200 'assessmentid' => new external_value(PARAM_INT, 'Assessment id'),
1201 'mode' => new external_value(PARAM_ALPHA, 'The form mode (assessment or preview)', VALUE_DEFAULT, 'assessment'),
1202 )
1203 );
1204 }
1205
1206
1207 /**
1208 * Retrieves the assessment form definition (data required to be able to display the assessment form).
1209 *
1210 * @param int $assessmentid the assessment id
1211 * @param string $mode the form mode (assessment or preview)
1212 * @return array containing the assessment and warnings.
1213 * @since Moodle 3.4
1214 * @throws moodle_exception
1215 */
1216 public static function get_assessment_form_definition($assessmentid, $mode = 'assessment') {
1217 global $DB, $USER;
1218
1219 $params = self::validate_parameters(
1220 self::get_assessment_form_definition_parameters(), array('assessmentid' => $assessmentid, 'mode' => $mode)
1221 );
1222 $warnings = $pending = array();
1223
1224 if ($params['mode'] != 'assessment' && $params['mode'] != 'preview') {
1225 throw new invalid_parameter_exception('Invalid value for mode parameter (value: ' . $params['mode'] . ')');
1226 }
1227
1228 // Get and validate the assessment, submission and workshop.
1229 $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
1230 $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
1231 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1232
1233 // Check we can edit the assessment (so we can get the form data).
1234 $workshop->check_edit_assessment($assessment, $submission);
1235
1236 $cansetassessmentweight = has_capability('mod/workshop:allocate', $context);
1237 $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id);
1238
1239 // Retrieve the data from the strategy plugin.
1240 $strategy = $workshop->grading_strategy_instance();
1241 $strategyname = str_replace('_strategy', '', get_class($strategy)); // Get strategy name.
1242 $mform = $strategy->get_assessment_form(null, $params['mode'], $assessment, true,
1243 array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending)));
1244 $formdata = $mform->get_customdata();
1245
1246 $result = array(
1247 'dimenssionscount' => $formdata['nodims'],
1248 'descriptionfiles' => external_util::get_area_files($context->id, $strategyname, 'description'),
1249 'warnings' => $warnings
1250 );
1251 // Include missing dimension fields.
1252 for ($i = 0; $i < $formdata['nodims']; $i++) {
1253 $formdata['fields']->{'gradeid__idx_' . $i} = 0;
1254 $formdata['fields']->{'peercomment__idx_' . $i} = '';
1255 }
1256
1257 // Convert all the form data for external.
1258 foreach (array('options', 'fields', 'current') as $typeofdata) {
1259 $result[$typeofdata] = array();
1260
1261 if (!empty($formdata[$typeofdata])) {
1262 $alldata = (array) $formdata[$typeofdata];
1263 foreach ($alldata as $key => $val) {
1264 if (strpos($key, 'peercomment__idx_') === 0) {
1265 // Format reviewer comment.
1266 list($val, $format) = external_format_text($val, FORMAT_MOODLE, $context->id);
1267 } else if (strpos($key, 'description__idx_')) {
1268 // Format dimension description.
1269 $id = str_replace('description__idx_', '', $key);
1270 list($val, $format) = external_format_text($val, $alldata['dimensionid__idx_' . $id . 'format'],
1271 $context->id, $strategyname, 'description', $alldata['dimensionid__idx_' . $id]);
1272 }
1273 $result[$typeofdata][] = array(
1274 'name' => $key,
1275 'value' => $val
1276 );
1277 }
1278 }
1279 }
1280
1281 return $result;
1282 }
1283
1284 /**
1285 * Returns description of method result value
1286 *
1287 * @return external_description
1288 * @since Moodle 3.4
1289 */
1290 public static function get_assessment_form_definition_returns() {
1291 return new external_single_structure(
1292 array(
1293 'dimenssionscount' => new external_value(PARAM_INT, 'The number of dimenssions used by the form.'),
1294 'descriptionfiles' => new external_files('Files in the description text'),
1295 'options' => new external_multiple_structure(
1296 new external_single_structure(
1297 array(
1298 'name' => new external_value(PARAM_ALPHANUMEXT, 'Option name.'),
1299 'value' => new external_value(PARAM_NOTAGS, 'Option value.')
1300 )
1301 ), 'The form options.'
1302 ),
1303 'fields' => new external_multiple_structure(
1304 new external_single_structure(
1305 array(
1306 'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'),
1307 'value' => new external_value(PARAM_RAW, 'Field default value.')
1308 )
1309 ), 'The form fields.'
1310 ),
1311 'current' => new external_multiple_structure(
1312 new external_single_structure(
1313 array(
1314 'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'),
1315 'value' => new external_value(PARAM_RAW, 'Current field value.')
1316 )
1317 ), 'The current field values.'
1318 ),
1319 'warnings' => new external_warnings()
1320 )
1321 );
1322 }
9f1ab2db 1323}