2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Workshop external API
20 * @package mod_workshop
22 * @copyright 2017 Juan Leyva <juan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
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;
37 * Workshop external functions
39 * @package mod_workshop
41 * @copyright 2017 Juan Leyva <juan@moodle.com>
42 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 class mod_workshop_external extends external_api {
48 * Describes the parameters for get_workshops_by_courses.
50 * @return external_function_parameters
53 public static function get_workshops_by_courses_parameters() {
54 return new external_function_parameters (
56 'courseids' => new external_multiple_structure(
57 new external_value(PARAM_INT, 'Course id'), 'Array of course ids', VALUE_DEFAULT, array()
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.
67 * @param array $courseids course ids
68 * @return array of warnings and workshops
71 public static function get_workshops_by_courses($courseids = array()) {
75 $returnedworkshops = array();
78 'courseids' => $courseids,
80 $params = self::validate_parameters(self::get_workshops_by_courses_parameters(), $params);
83 if (empty($params['courseids'])) {
84 $mycourses = enrol_get_my_courses();
85 $params['courseids'] = array_keys($mycourses);
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);
110 'workshops' => $returnedworkshops,
111 'warnings' => $warnings
117 * Describes the get_workshops_by_courses return value.
119 * @return external_single_structure
122 public static function get_workshops_by_courses_returns() {
123 return new external_single_structure(
125 'workshops' => new external_multiple_structure(
126 workshop_summary_exporter::get_read_structure()
128 'warnings' => new external_warnings(),
134 * Utility function for validating a workshop.
136 * @param int $workshopid workshop instance id
137 * @return array array containing the workshop object, course, context and course module objects
140 protected static function validate_workshop($workshopid) {
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);
157 * Describes the parameters for get_workshop_access_information.
159 * @return external_external_function_parameters
162 public static function get_workshop_access_information_parameters() {
163 return new external_function_parameters (
165 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.')
171 * Return access information for a given workshop.
173 * @param int $workshopid workshop instance id
174 * @return array of warnings and the access information
176 * @throws moodle_exception
178 public static function get_workshop_access_information($workshopid) {
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']);
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);
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;
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();
210 * Describes the get_workshop_access_information return value.
212 * @return external_single_structure
215 public static function get_workshop_access_information_returns() {
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()
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.');
242 return new external_single_structure($structure);
246 * Describes the parameters for get_user_plan.
248 * @return external_external_function_parameters
251 public static function get_user_plan_parameters() {
252 return new external_function_parameters (
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),
261 * Return the planner information for the given user.
263 * @param int $workshopid workshop instance id
264 * @param int $userid user id
265 * @return array of warnings and the user plan
267 * @throws moodle_exception
269 public static function get_user_plan($workshopid, $userid = 0) {
273 'workshopid' => $workshopid,
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) {
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');
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);
304 $userplan['phases'][$phasecode]['tasks'][$taskcode] = (array) $task;
306 foreach ($userplan['phases'][$phasecode]['actions'] as $actioncode => $action) {
307 if ($action->url instanceof moodle_url) {
308 $action->url = $action->url->out(false);
310 $userplan['phases'][$phasecode]['actions'][$actioncode] = (array) $action;
314 $result['userplan'] = $userplan;
315 $result['warnings'] = array();
320 * Describes the get_user_plan return value.
322 * @return external_single_structure
325 public static function get_user_plan_returns() {
326 return new external_single_structure(
328 'userplan' => new external_single_structure(
330 'phases' => new external_multiple_structure(
331 new external_single_structure(
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(
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.'),
348 'actions' => new external_multiple_structure(
349 new external_single_structure(
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),
361 'examples' => new external_multiple_structure(
362 new external_single_structure(
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.'),
374 'warnings' => new external_warnings(),
380 * Describes the parameters for view_workshop.
382 * @return external_function_parameters
385 public static function view_workshop_parameters() {
386 return new external_function_parameters (
388 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id'),
394 * Trigger the course module viewed event and update the module completion status.
396 * @param int $workshopid workshop instance id
397 * @return array of warnings and status result
399 * @throws moodle_exception
401 public static function view_workshop($workshopid) {
403 $params = array('workshopid' => $workshopid);
404 $params = self::validate_parameters(self::view_workshop_parameters(), $params);
407 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
409 $workshop->set_module_viewed();
413 'warnings' => $warnings,
419 * Describes the view_workshop return value.
421 * @return external_single_structure
424 public static function view_workshop_returns() {
425 return new external_single_structure(
427 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
428 'warnings' => new external_warnings(),
434 * Returns the description of the external function parameters.
436 * @return external_function_parameters
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',
447 'attachmentsid' => new external_value(PARAM_INT, 'The draft file area id for attachments', VALUE_DEFAULT, 0),
452 * Add a new submission to a given workshop.
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.
462 * @throws moodle_exception
464 public static function add_submission($workshopid, $title, $content = '', $contentformat = FORMAT_MOODLE,
465 $inlineattachmentsid = 0, $attachmentsid = 0) {
468 $params = self::validate_parameters(self::add_submission_parameters(), array(
469 'workshopid' => $workshopid,
471 'content' => $content,
472 'contentformat' => $contentformat,
473 'inlineattachmentsid' => $inlineattachmentsid,
474 'attachmentsid' => $attachmentsid,
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');
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'],
500 $submission->attachment_filemanager = $params['attachmentsid'];
502 if (empty($submission->title)) {
503 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title');
506 $errors = $workshop->validate_submission_data((array) $submission);
507 // We can get several errors, return them in warnings.
508 if (!empty($errors)) {
510 foreach ($errors as $itemname => $message) {
514 'warningcode' => 'fielderror',
515 'message' => s($message)
520 'warnings' => $warnings
523 $submission->id = $workshop->edit_submission($submission);
526 'submissionid' => $submission->id,
527 'warnings' => $warnings
533 * Returns the description of the external function return value.
535 * @return external_description
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()
547 * Returns the description of the external function parameters.
549 * @return external_function_parameters
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',
560 'attachmentsid' => new external_value(PARAM_INT, 'The draft file area id for attachments', VALUE_DEFAULT, 0),
566 * Updates the given submission.
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.
576 * @throws moodle_exception
578 public static function update_submission($submissionid, $title, $content = '', $contentformat = FORMAT_MOODLE,
579 $inlineattachmentsid = 0, $attachmentsid = 0) {
582 $params = self::validate_parameters(self::update_submission_parameters(), array(
583 'submissionid' => $submissionid,
585 'content' => $content,
586 'contentformat' => $contentformat,
587 'inlineattachmentsid' => $inlineattachmentsid,
588 'attachmentsid' => $attachmentsid,
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');
605 // Prepare the submission object.
606 $submission->title = trim($params['title']);
607 if (empty($submission->title)) {
608 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'title');
610 $submission->content_editor = array(
611 'text' => $params['content'],
612 'format' => $params['contentformat'],
613 'itemid' => $params['inlineattachmentsid'],
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)) {
621 foreach ($errors as $itemname => $message) {
625 'warningcode' => 'fielderror',
626 'message' => s($message)
631 $submission->id = $workshop->edit_submission($submission);
636 'warnings' => $warnings
641 * Returns the description of the external function return value.
643 * @return external_description
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()
654 * Returns the description of the external function parameters.
656 * @return external_function_parameters
659 public static function delete_submission_parameters() {
660 return new external_function_parameters(
662 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
669 * Deletes the given submission.
671 * @param int $submissionid the submission id.
672 * @return array containing the result status and warnings.
674 * @throws moodle_exception
676 public static function delete_submission($submissionid) {
679 $params = self::validate_parameters(self::delete_submission_parameters(), array('submissionid' => $submissionid));
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');
698 $workshop->delete_submission($submission);
702 'warnings' => $warnings
707 * Returns the description of the external function return value.
709 * @return external_description
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()
720 * Helper method for returning the submission data according the current user capabilities and current phase.
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
730 protected static function prepare_submission_for_external($submission, workshop $workshop, $canviewauthorpublished = null,
731 $canviewauthornames = null, $canviewallsubmissions = null) {
734 if (is_null($canviewauthorpublished)) {
735 $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $workshop->context);
737 if (is_null($canviewauthornames)) {
738 $canviewauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context);
740 if (is_null($canviewallsubmissions)) {
741 $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $workshop->context);
744 $ownsubmission = $submission->authorid == $USER->id;
745 if (!$canviewauthornames && !$ownsubmission) {
746 $submission->authorid = 0;
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});
764 * Returns description of method parameters
766 * @return external_function_parameters
769 public static function get_submissions_parameters() {
770 return new external_function_parameters(
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',
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.',
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),
785 * Retrieves all the workshop submissions visible by the current user or the one done by the given user.
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
794 * @throws moodle_exception
796 public static function get_submissions($workshopid, $userid = 0, $groupid = 0, $page = 0, $perpage = 0) {
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();
804 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
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');
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');
828 list($submissionsrecords, $totalcount) =
829 $workshop->get_visible_submissions($params['userid'], $groupid, $params['page'], $params['perpage']);
833 $canviewauthorpublished = has_capability('mod/workshop:viewauthorpublished', $context);
834 $canviewauthornames = has_capability('mod/workshop:viewauthornames', $context);
835 $canviewallsubmissions = has_capability('mod/workshop:viewallsubmissions', $context);
837 $related = array('context' => $context);
838 foreach ($submissionsrecords as $submission) {
839 $submission = self::prepare_submission_for_external($submission, $workshop, $canviewauthorpublished,
840 $canviewauthornames, $canviewallsubmissions);
842 $exporter = new submission_exporter($submission, $related);
843 $submissions[] = $exporter->export($PAGE->get_renderer('core'));
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()])) {
853 $totalfilesize += $file->get_filesize();
858 'submissions' => $submissions,
859 'totalcount' => $totalcount,
860 'totalfilesize' => $totalfilesize,
865 * Returns description of method result value
867 * @return external_description
870 public static function get_submissions_returns() {
871 return new external_single_structure(
873 'submissions' => new external_multiple_structure(
874 submission_exporter::get_read_structure()
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()
884 * Helper method for validating a submission.
886 * @param stdClass $submission submission object
887 * @param workshop $workshop workshop instance
891 protected static function validate_submission($submission, workshop $workshop) {
894 $workshopclosed = $workshop->phase == workshop::PHASE_CLOSED;
895 $canviewpublished = has_capability('mod/workshop:viewpublishedsubmissions', $workshop->context);
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.
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');
909 throw new moodle_exception('nopermissions', 'error', '', 'view submission');
914 * Returns the description of the external function parameters.
916 * @return external_function_parameters
919 public static function get_submission_parameters() {
920 return new external_function_parameters(
922 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
929 * Retrieves the given submission.
931 * @param int $submissionid the submission id
932 * @return array containing the submission and warnings.
934 * @throws moodle_exception
936 public static function get_submission($submissionid) {
937 global $USER, $DB, $PAGE;
939 $params = self::validate_parameters(self::get_submission_parameters(), array('submissionid' => $submissionid));
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);
946 self::validate_submission($submission, $workshop);
948 $submission = self::prepare_submission_for_external($submission, $workshop);
950 $related = array('context' => $context);
951 $exporter = new submission_exporter($submission, $related);
953 'submission' => $exporter->export($PAGE->get_renderer('core')),
954 'warnings' => $warnings
959 * Returns description of method result value
961 * @return external_description
964 public static function get_submission_returns() {
965 return new external_single_structure(
967 'submission' => submission_exporter::get_read_structure(),
968 'warnings' => new external_warnings()
974 * Helper method for validating if the current user can view the submission assessments.
976 * @param stdClass $submission submission object
977 * @param workshop $workshop workshop instance
981 protected static function check_view_submission_assessments($submission, workshop $workshop) {
984 $ownsubmission = $submission->authorid == $USER->id;
985 $canview = has_capability('mod/workshop:viewallassessments', $workshop->context) ||
986 ($ownsubmission && $workshop->assessments_available());
989 // Here we should check if the user share group.
990 if ($submission->authorid != $USER->id &&
991 !groups_user_groups_visible($workshop->course, $submission->authorid, $workshop->cm)) {
992 throw new moodle_exception('notingroup');
995 throw new moodle_exception('nopermissions', 'error', '', 'view assessment');
1000 * Helper method for returning the assessment data according the current user capabilities and current phase.
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
1007 protected static function prepare_assessment_for_external($assessment, workshop $workshop) {
1009 static $canviewallassessments = null;
1010 static $canviewreviewers = null;
1011 static $canoverridegrades = null;
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});
1021 if (is_null($canviewallassessments)) {
1022 $canviewallassessments = has_capability('mod/workshop:viewallassessments', $workshop->context);
1024 if (is_null($canviewreviewers)) {
1025 $canviewreviewers = has_capability('mod/workshop:viewreviewernames', $workshop->context);
1027 if (is_null($canoverridegrades)) {
1028 $canoverridegrades = has_capability('mod/workshop:overridegrades', $workshop->context);
1031 $isreviewer = $assessment->reviewerid == $USER->id;
1033 if (!$isreviewer && is_null($assessment->grade) && !$canviewallassessments) {
1034 // Students do not see peer-assessment that are not graded yet.
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});
1048 if (!$isreviewer && !$canviewreviewers) {
1049 $assessment->reviewerid = 0;
1056 * Returns the description of the external function parameters.
1058 * @return external_function_parameters
1061 public static function get_submission_assessments_parameters() {
1062 return new external_function_parameters(
1064 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
1071 * Retrieves the given submission assessments.
1073 * @param int $submissionid the submission id
1074 * @return array containing the assessments and warnings.
1076 * @throws moodle_exception
1078 public static function get_submission_assessments($submissionid) {
1079 global $USER, $DB, $PAGE;
1081 $params = self::validate_parameters(self::get_submission_assessments_parameters(), array('submissionid' => $submissionid));
1082 $warnings = $assessments = array();
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);
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);
1092 $related = array('context' => $context);
1093 foreach ($assessmentsrecords as $assessment) {
1094 $assessment = self::prepare_assessment_for_external($assessment, $workshop);
1095 if (empty($assessment)) {
1098 $exporter = new assessment_exporter($assessment, $related);
1099 $assessments[] = $exporter->export($PAGE->get_renderer('core'));
1103 'assessments' => $assessments,
1104 'warnings' => $warnings
1109 * Returns description of method result value
1111 * @return external_description
1114 public static function get_submission_assessments_returns() {
1115 return new external_single_structure(
1117 'assessments' => new external_multiple_structure(
1118 assessment_exporter::get_read_structure()
1120 'warnings' => new external_warnings()
1126 * Returns the description of the external function parameters.
1128 * @return external_function_parameters
1131 public static function get_assessment_parameters() {
1132 return new external_function_parameters(
1134 'assessmentid' => new external_value(PARAM_INT, 'Assessment id'),
1141 * Retrieves the given assessment.
1143 * @param int $assessmentid the assessment id
1144 * @return array containing the assessment and warnings.
1146 * @throws moodle_exception
1148 public static function get_assessment($assessmentid) {
1151 $params = self::validate_parameters(self::get_assessment_parameters(), array('assessmentid' => $assessmentid));
1152 $warnings = array();
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);
1159 // Check that we can get the assessment.
1160 $workshop->check_view_assessment($assessment, $submission);
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');
1167 $related = array('context' => $context);
1168 $exporter = new assessment_exporter($assessment, $related);
1171 'assessment' => $exporter->export($PAGE->get_renderer('core')),
1172 'warnings' => $warnings
1177 * Returns description of method result value
1179 * @return external_description
1182 public static function get_assessment_returns() {
1183 return new external_single_structure(
1185 'assessment' => assessment_exporter::get_read_structure(),
1186 'warnings' => new external_warnings()
1192 * Returns the description of the external function parameters.
1194 * @return external_function_parameters
1197 public static function get_assessment_form_definition_parameters() {
1198 return new external_function_parameters(
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'),
1208 * Retrieves the assessment form definition (data required to be able to display the assessment form).
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.
1214 * @throws moodle_exception
1216 public static function get_assessment_form_definition($assessmentid, $mode = 'assessment') {
1219 $params = self::validate_parameters(
1220 self::get_assessment_form_definition_parameters(), array('assessmentid' => $assessmentid, 'mode' => $mode)
1222 $warnings = $pending = array();
1224 if ($params['mode'] != 'assessment' && $params['mode'] != 'preview') {
1225 throw new invalid_parameter_exception('Invalid value for mode parameter (value: ' . $params['mode'] . ')');
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);
1233 // Check we can edit the assessment (so we can get the form data).
1234 $workshop->check_edit_assessment($assessment, $submission);
1236 $cansetassessmentweight = has_capability('mod/workshop:allocate', $context);
1237 $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id);
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();
1247 'dimenssionscount' => $formdata['nodims'],
1248 'descriptionfiles' => external_util::get_area_files($context->id, $strategyname, 'description'),
1249 'warnings' => $warnings
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} = '';
1257 // Convert all the form data for external.
1258 foreach (array('options', 'fields', 'current') as $typeofdata) {
1259 $result[$typeofdata] = array();
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]);
1273 $result[$typeofdata][] = array(
1285 * Returns description of method result value
1287 * @return external_description
1290 public static function get_assessment_form_definition_returns() {
1291 return new external_single_structure(
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(
1298 'name' => new external_value(PARAM_ALPHANUMEXT, 'Option name.'),
1299 'value' => new external_value(PARAM_NOTAGS, 'Option value.')
1301 ), 'The form options.'
1303 'fields' => new external_multiple_structure(
1304 new external_single_structure(
1306 'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'),
1307 'value' => new external_value(PARAM_RAW, 'Field default value.')
1309 ), 'The form fields.'
1311 'current' => new external_multiple_structure(
1312 new external_single_structure(
1314 'name' => new external_value(PARAM_ALPHANUMEXT, 'Field name.'),
1315 'value' => new external_value(PARAM_RAW, 'Current field value.')
1317 ), 'The current field values.'
1319 'warnings' => new external_warnings()
1325 * Returns the description of the external function parameters.
1327 * @return external_function_parameters
1330 public static function get_reviewer_assessments_parameters() {
1331 return new external_function_parameters(
1333 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
1334 'userid' => new external_value(PARAM_INT, 'User id who did the assessment review (empty or 0 for current user).',
1342 * Retrieves all the assessments reviewed by the given user.
1344 * @param int $workshopid the workshop instance id
1345 * @param int $userid the reviewer user id
1346 * @return array containing the user assessments and warnings.
1348 * @throws moodle_exception
1350 public static function get_reviewer_assessments($workshopid, $userid = 0) {
1351 global $USER, $DB, $PAGE;
1353 $params = self::validate_parameters(
1354 self::get_reviewer_assessments_parameters(), array('workshopid' => $workshopid, 'userid' => $userid)
1356 $warnings = $assessments = array();
1358 // Get and validate the submission and workshop.
1359 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
1361 // Extra checks so only users with permissions can view other users assessments.
1362 if (empty($params['userid']) || $params['userid'] == $USER->id) {
1363 $userid = $USER->id;
1364 list($assessed, $notice) = $workshop->check_examples_assessed_before_assessment($userid);
1366 throw new moodle_exception($notice, 'mod_workshop');
1368 if ($workshop->phase < workshop::PHASE_ASSESSMENT) { // Can view assessments only in assessment phase onwards.
1369 throw new moodle_exception('nopermissions', 'error', '', 'view assessments');
1372 require_capability('mod/workshop:viewallassessments', $context);
1373 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
1374 core_user::require_active_user($user);
1375 if (!$workshop->check_group_membership($user->id)) {
1376 throw new moodle_exception('notingroup');
1378 $userid = $user->id;
1380 // Now get all my assessments (includes those pending review).
1381 $assessmentsrecords = $workshop->get_assessments_by_reviewer($userid);
1383 $related = array('context' => $context);
1384 foreach ($assessmentsrecords as $assessment) {
1385 $assessment = self::prepare_assessment_for_external($assessment, $workshop);
1386 if (empty($assessment)) {
1389 $exporter = new assessment_exporter($assessment, $related);
1390 $assessments[] = $exporter->export($PAGE->get_renderer('core'));
1394 'assessments' => $assessments,
1395 'warnings' => $warnings
1400 * Returns description of method result value
1402 * @return external_description
1405 public static function get_reviewer_assessments_returns() {
1406 return new external_single_structure(
1408 'assessments' => new external_multiple_structure(
1409 assessment_exporter::get_read_structure()
1411 'warnings' => new external_warnings()