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 phase is not valid or if we don't have enough permissions to see it.
1039 if ($workshop->phase < workshop::PHASE_EVALUATION || !($isreviewer || $canviewallassessments)) {
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 view the assessment (so we can get the form data).
1234 $workshop->check_view_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()
1417 * Returns the description of the external function parameters.
1419 * @return external_function_parameters
1422 public static function update_assessment_parameters() {
1423 return new external_function_parameters(
1425 'assessmentid' => new external_value(PARAM_INT, 'Assessment id.'),
1426 'data' => new external_multiple_structure (
1427 new external_single_structure(
1429 'name' => new external_value(PARAM_ALPHANUMEXT,
1430 'The assessment data (use WS get_assessment_form_definition for obtaining the data to sent).
1431 Apart from that data, you can optionally send:
1432 feedbackauthor (str); the feedback for the submission author
1433 feedbackauthorformat (int); the format of the feedbackauthor
1434 feedbackauthorinlineattachmentsid (int); the draft file area for the editor attachments
1435 feedbackauthorattachmentsid (int); the draft file area id for the feedback attachments'
1437 'value' => new external_value(PARAM_RAW, 'The value of the option.')
1439 ), 'Assessment data'
1447 * Updates an assessment.
1449 * @param int $assessmentid the assessment id
1450 * @param array $data the assessment data
1451 * @return array indicates if the assessment was updated, the new raw grade and possible warnings.
1453 * @throws moodle_exception
1455 public static function update_assessment($assessmentid, $data) {
1458 $params = self::validate_parameters(
1459 self::update_assessment_parameters(), array('assessmentid' => $assessmentid, 'data' => $data)
1461 $warnings = array();
1463 // Get and validate the assessment, submission and workshop.
1464 $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
1465 $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
1466 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1468 // Check we can edit the assessment.
1469 $workshop->check_edit_assessment($assessment, $submission);
1472 $data = new stdClass;
1473 $data->feedbackauthor_editor = array();
1475 foreach ($params['data'] as $wsdata) {
1476 $name = trim($wsdata['name']);
1478 case 'feedbackauthor':
1479 $data->feedbackauthor_editor['text'] = $wsdata['value'];
1481 case 'feedbackauthorformat':
1482 $data->feedbackauthor_editor['format'] = clean_param($wsdata['value'], PARAM_FORMAT);
1484 case 'feedbackauthorinlineattachmentsid':
1485 $data->feedbackauthor_editor['itemid'] = clean_param($wsdata['value'], PARAM_INT);
1487 case 'feedbackauthorattachmentsid':
1488 $data->feedbackauthorattachment_filemanager = clean_param($wsdata['value'], PARAM_INT);
1491 $data->{$wsdata['name']} = $wsdata['value']; // Validation will be done in the form->validation.
1495 $cansetassessmentweight = has_capability('mod/workshop:allocate', $context);
1496 $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id);
1497 // Retrieve the data from the strategy plugin.
1498 $strategy = $workshop->grading_strategy_instance();
1499 $mform = $strategy->get_assessment_form(null, 'assessment', $assessment, true,
1500 array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending)));
1502 $errors = $mform->validation((array) $data, array());
1503 // We can get several errors, return them in warnings.
1504 if (!empty($errors)) {
1507 foreach ($errors as $itemname => $message) {
1508 $warnings[] = array(
1509 'item' => $itemname,
1511 'warningcode' => 'fielderror',
1512 'message' => s($message)
1516 $rawgrade = $workshop->edit_assessment($assessment, $submission, $data, $strategy);
1521 'status' => $status,
1522 'rawgrade' => $rawgrade,
1523 'warnings' => $warnings,
1528 * Returns description of method result value
1530 * @return external_description
1533 public static function update_assessment_returns() {
1534 return new external_single_structure(
1536 'status' => new external_value(PARAM_BOOL, 'status: true if the assessment was added or updated false otherwise.'),
1537 'rawgrade' => new external_value(PARAM_FLOAT, 'Raw percentual grade (0.00000 to 100.00000) for submission.',
1539 'warnings' => new external_warnings()
1545 * Returns the description of the external function parameters.
1547 * @return external_external_function_parameters
1550 public static function get_grades_parameters() {
1551 return new external_function_parameters (
1553 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
1554 'userid' => new external_value(PARAM_INT, 'User id (empty or 0 for current user).', VALUE_DEFAULT, 0),
1560 * Returns the grades information for the given workshop and user.
1562 * @param int $workshopid workshop instance id
1563 * @param int $userid user id
1564 * @return array of warnings and the user plan
1566 * @throws moodle_exception
1568 public static function get_grades($workshopid, $userid = 0) {
1572 'workshopid' => $workshopid,
1573 'userid' => $userid,
1575 $params = self::validate_parameters(self::get_grades_parameters(), $params);
1576 $warnings = array();
1578 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
1580 // Extra checks so only users with permissions can view other users plans.
1581 if (empty($params['userid']) || $params['userid'] == $USER->id) {
1582 $userid = $USER->id;
1584 require_capability('mod/workshop:viewallassessments', $context);
1585 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
1586 core_user::require_active_user($user);
1587 if (!$workshop->check_group_membership($user->id)) {
1588 throw new moodle_exception('notingroup');
1590 $userid = $user->id;
1593 $finalgrades = $workshop->get_gradebook_grades($userid);
1595 $result = array('warnings' => $warnings);
1596 if ($finalgrades !== false) {
1597 if (!empty($finalgrades->submissiongrade)) {
1598 if (is_numeric($finalgrades->submissiongrade->grade)) {
1599 $result['submissionrawgrade'] = $finalgrades->submissiongrade->grade;
1601 $result['submissionlongstrgrade'] = $finalgrades->submissiongrade->str_long_grade;
1602 $result['submissiongradehidden'] = $finalgrades->submissiongrade->hidden;
1604 if (!empty($finalgrades->assessmentgrade)) {
1605 if (is_numeric($finalgrades->assessmentgrade->grade)) {
1606 $result['assessmentrawgrade'] = $finalgrades->assessmentgrade->grade;
1608 $result['assessmentlongstrgrade'] = $finalgrades->assessmentgrade->str_long_grade;
1609 $result['assessmentgradehidden'] = $finalgrades->assessmentgrade->hidden;
1617 * Returns description of method result value.
1619 * @return external_single_structure
1622 public static function get_grades_returns() {
1623 return new external_single_structure(
1625 'assessmentrawgrade' => new external_value(PARAM_FLOAT, 'The assessment raw (numeric) grade.', VALUE_OPTIONAL),
1626 'assessmentlongstrgrade' => new external_value(PARAM_NOTAGS, 'The assessment string grade.', VALUE_OPTIONAL),
1627 'assessmentgradehidden' => new external_value(PARAM_BOOL, 'Whether the grade is hidden or not.', VALUE_OPTIONAL),
1628 'submissionrawgrade' => new external_value(PARAM_FLOAT, 'The submission raw (numeric) grade.', VALUE_OPTIONAL),
1629 'submissionlongstrgrade' => new external_value(PARAM_NOTAGS, 'The submission string grade.', VALUE_OPTIONAL),
1630 'submissiongradehidden' => new external_value(PARAM_BOOL, 'Whether the grade is hidden or not.', VALUE_OPTIONAL),
1631 'warnings' => new external_warnings(),
1637 * Returns the description of the external function parameters.
1639 * @return external_function_parameters
1642 public static function evaluate_assessment_parameters() {
1643 return new external_function_parameters(
1645 'assessmentid' => new external_value(PARAM_INT, 'Assessment id.'),
1646 'feedbacktext' => new external_value(PARAM_RAW, 'The feedback for the reviewer.', VALUE_DEFAULT, ''),
1647 'feedbackformat' => new external_value(PARAM_INT, 'The feedback format for text.', VALUE_DEFAULT, FORMAT_MOODLE),
1648 'weight' => new external_value(PARAM_INT, 'The new weight for the assessment.', VALUE_DEFAULT, 1),
1649 'gradinggradeover' => new external_value(PARAM_ALPHANUMEXT, 'The new grading grade.', VALUE_DEFAULT, ''),
1656 * Evaluates an assessment (used by teachers for provide feedback to the reviewer).
1658 * @param int $assessmentid the assessment id
1659 * @param str $feedbacktext the feedback for the reviewer
1660 * @param int $feedbackformat the feedback format for the reviewer text
1661 * @param int $weight the new weight for the assessment
1662 * @param mixed $gradinggradeover the new grading grade (empty for no overriding the grade)
1663 * @return array containing the status and warnings.
1665 * @throws moodle_exception
1667 public static function evaluate_assessment($assessmentid, $feedbacktext = '', $feedbackformat = FORMAT_MOODLE, $weight = 1,
1668 $gradinggradeover = '') {
1671 $params = self::validate_parameters(
1672 self::evaluate_assessment_parameters(),
1674 'assessmentid' => $assessmentid,
1675 'feedbacktext' => $feedbacktext,
1676 'feedbackformat' => $feedbackformat,
1677 'weight' => $weight,
1678 'gradinggradeover' => $gradinggradeover,
1681 $warnings = array();
1683 // Get and validate the assessment, submission and workshop.
1684 $assessment = $DB->get_record('workshop_assessments', array('id' => $params['assessmentid']), '*', MUST_EXIST);
1685 $submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid), '*', MUST_EXIST);
1686 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1688 // Check we can evaluate the assessment.
1689 $workshop->check_view_assessment($assessment, $submission);
1690 $cansetassessmentweight = has_capability('mod/workshop:allocate', $context);
1691 $canoverridegrades = has_capability('mod/workshop:overridegrades', $context);
1692 if (!$canoverridegrades && !$cansetassessmentweight) {
1693 throw new moodle_exception('nopermissions', 'error', '', 'evaluate assessments');
1697 $data = new stdClass;
1698 $data->asid = $assessment->id;
1699 $data->feedbackreviewer_editor = array(
1700 'text' => $params['feedbacktext'],
1701 'format' => $params['feedbackformat'],
1703 $data->weight = $params['weight'];
1704 $data->gradinggradeover = $params['gradinggradeover'];
1708 'editableweight' => $cansetassessmentweight,
1709 'overridablegradinggrade' => $canoverridegrades
1711 $feedbackform = $workshop->get_feedbackreviewer_form(null, $assessment, $options);
1713 $errors = $feedbackform->validation((array) $data, array());
1714 // We can get several errors, return them in warnings.
1715 if (!empty($errors)) {
1717 foreach ($errors as $itemname => $message) {
1718 $warnings[] = array(
1719 'item' => $itemname,
1721 'warningcode' => 'fielderror',
1722 'message' => s($message)
1726 $workshop->evaluate_assessment($assessment, $data, $cansetassessmentweight, $canoverridegrades);
1731 'status' => $status,
1732 'warnings' => $warnings,
1737 * Returns description of method result value
1739 * @return external_description
1742 public static function evaluate_assessment_returns() {
1743 return new external_single_structure(
1745 'status' => new external_value(PARAM_BOOL, 'status: true if the assessment was evaluated, false otherwise.'),
1746 'warnings' => new external_warnings()
1752 * Returns description of method parameters
1754 * @return external_function_parameters
1757 public static function get_grades_report_parameters() {
1758 return new external_function_parameters(
1760 'workshopid' => new external_value(PARAM_INT, 'Workshop instance id.'),
1761 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.',
1763 'sortby' => new external_value(PARAM_ALPHA, 'sort by this element: lastname, firstname, submissiontitle,
1764 submissionmodified, submissiongrade, gradinggrade.', VALUE_DEFAULT, 'lastname'),
1765 'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'ASC'),
1766 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0),
1767 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0),
1773 * Retrieves the assessment grades report.
1775 * @param int $workshopid the workshop instance id
1776 * @param int $groupid (optional) group id, 0 means that the function will determine the user group
1777 * @param string $sortby sort by this element
1778 * @param string $sortdirection sort direction: ASC or DESC
1779 * @param int $page page of records to return
1780 * @param int $perpage number of records to return per page
1781 * @return array of warnings and the report data
1783 * @throws moodle_exception
1785 public static function get_grades_report($workshopid, $groupid = 0, $sortby = 'lastname', $sortdirection = 'ASC',
1786 $page = 0, $perpage = 0) {
1789 $params = array('workshopid' => $workshopid, 'groupid' => $groupid, 'sortby' => $sortby, 'sortdirection' => $sortdirection,
1790 'page' => $page, 'perpage' => $perpage);
1791 $params = self::validate_parameters(self::get_grades_report_parameters(), $params);
1792 $submissions = $warnings = array();
1794 $sortallowedvalues = array('lastname', 'firstname', 'submissiontitle', 'submissionmodified', 'submissiongrade',
1796 if (!in_array($params['sortby'], $sortallowedvalues)) {
1797 throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' .
1798 'allowed values are: ' . implode(',', $sortallowedvalues));
1801 $sortdirection = strtoupper($params['sortdirection']);
1802 $directionallowedvalues = array('ASC', 'DESC');
1803 if (!in_array($sortdirection, $directionallowedvalues)) {
1804 throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' .
1805 'allowed values are: ' . implode(',', $directionallowedvalues));
1808 list($workshop, $course, $cm, $context) = self::validate_workshop($params['workshopid']);
1809 require_capability('mod/workshop:viewallassessments', $context);
1811 if (!empty($params['groupid'])) {
1812 $groupid = $params['groupid'];
1813 // Determine is the group is visible to user.
1814 if (!groups_group_visible($groupid, $course, $cm)) {
1815 throw new moodle_exception('notingroup');
1818 // Check to see if groups are being used here.
1819 if ($groupmode = groups_get_activity_groupmode($cm)) {
1820 $groupid = groups_get_activity_group($cm);
1821 // Determine is the group is visible to user (this is particullary for the group 0 -> all groups).
1822 if (!groups_group_visible($groupid, $course, $cm)) {
1823 throw new moodle_exception('notingroup');
1830 if ($workshop->phase >= workshop::PHASE_SUBMISSION) {
1831 $showauthornames = has_capability('mod/workshop:viewauthornames', $context);
1832 $showreviewernames = has_capability('mod/workshop:viewreviewernames', $context);
1834 if ($workshop->phase >= workshop::PHASE_EVALUATION) {
1835 $showsubmissiongrade = true;
1836 $showgradinggrade = true;
1838 $showsubmissiongrade = false;
1839 $showgradinggrade = false;
1842 $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $params['page'], $params['perpage'],
1843 $params['sortby'], $sortdirection);
1845 if (!empty($data)) {
1846 // Populate the display options for the submissions report.
1847 $reportopts = new stdclass();
1848 $reportopts->showauthornames = $showauthornames;
1849 $reportopts->showreviewernames = $showreviewernames;
1850 $reportopts->sortby = $params['sortby'];
1851 $reportopts->sorthow = $sortdirection;
1852 $reportopts->showsubmissiongrade = $showsubmissiongrade;
1853 $reportopts->showgradinggrade = $showgradinggrade;
1854 $reportopts->workshopphase = $workshop->phase;
1856 $report = new workshop_grading_report($data, $reportopts);
1858 'report' => $report->export_data_for_external(),
1859 'warnings' => array(),
1863 throw new moodle_exception('nothingfound', 'workshop');
1867 * Returns description of method result value
1869 * @return external_description
1872 public static function get_grades_report_returns() {
1874 $reviewstructure = new external_single_structure(
1876 'userid' => new external_value(PARAM_INT, 'The id of the user (0 when is configured to do not display names).'),
1877 'assessmentid' => new external_value(PARAM_INT, 'The id of the assessment.'),
1878 'submissionid' => new external_value(PARAM_INT, 'The id of the submission assessed.'),
1879 'grade' => new external_value(PARAM_FLOAT, 'The grade for submission.'),
1880 'gradinggrade' => new external_value(PARAM_FLOAT, 'The grade for assessment.'),
1881 'gradinggradeover' => new external_value(PARAM_FLOAT, 'The aggregated grade overrided.'),
1882 'weight' => new external_value(PARAM_INT, 'The weight of the assessment for aggregation.'),
1886 return new external_single_structure(
1888 'report' => new external_single_structure(
1890 'grades' => new external_multiple_structure(
1891 new external_single_structure(
1893 'userid' => new external_value(PARAM_INT, 'The id of the user being displayed in the report.'),
1894 'submissionid' => new external_value(PARAM_INT, 'Submission id.'),
1895 'submissiontitle' => new external_value(PARAM_RAW, 'Submission title.'),
1896 'submissionmodified' => new external_value(PARAM_INT, 'Timestamp submission was updated.'),
1897 'submissiongrade' => new external_value(PARAM_FLOAT, 'Aggregated grade for the submission.',
1899 'gradinggrade' => new external_value(PARAM_FLOAT, 'Computed grade for the assessment.',
1901 'submissiongradeover' => new external_value(PARAM_FLOAT, 'Grade for the assessment overrided
1902 by the teacher.', VALUE_OPTIONAL),
1903 'submissiongradeoverby' => new external_value(PARAM_INT, 'The id of the user who overrided
1904 the grade.', VALUE_OPTIONAL),
1905 'submissionpublished' => new external_value(PARAM_INT, 'Whether is a submission published.',
1907 'reviewedby' => new external_multiple_structure($reviewstructure, 'The users who reviewed the
1908 user submission.', VALUE_OPTIONAL),
1909 'reviewerof' => new external_multiple_structure($reviewstructure, 'The assessments the user
1910 reviewed.', VALUE_OPTIONAL),
1914 'totalcount' => new external_value(PARAM_INT, 'Number of total submissions.'),
1917 'warnings' => new external_warnings()
1923 * Describes the parameters for view_submission.
1925 * @return external_function_parameters
1928 public static function view_submission_parameters() {
1929 return new external_function_parameters (
1931 'submissionid' => new external_value(PARAM_INT, 'Submission id'),
1937 * Trigger the submission viewed event.
1939 * @param int $submissionid submission id
1940 * @return array of warnings and status result
1942 * @throws moodle_exception
1944 public static function view_submission($submissionid) {
1947 $params = self::validate_parameters(self::view_submission_parameters(), array('submissionid' => $submissionid));
1948 $warnings = array();
1950 // Get and validate the submission and workshop.
1951 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
1952 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
1954 self::validate_submission($submission, $workshop);
1956 $workshop->set_submission_viewed($submission);
1960 'warnings' => $warnings,
1966 * Describes the view_submission return value.
1968 * @return external_single_structure
1971 public static function view_submission_returns() {
1972 return new external_single_structure(
1974 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
1975 'warnings' => new external_warnings(),
1981 * Returns the description of the external function parameters.
1983 * @return external_function_parameters
1986 public static function evaluate_submission_parameters() {
1987 return new external_function_parameters(
1989 'submissionid' => new external_value(PARAM_INT, 'submission id.'),
1990 'feedbacktext' => new external_value(PARAM_RAW, 'The feedback for the author.', VALUE_DEFAULT, ''),
1991 'feedbackformat' => new external_value(PARAM_INT, 'The feedback format for text.', VALUE_DEFAULT, FORMAT_MOODLE),
1992 'published' => new external_value(PARAM_BOOL, 'Publish the submission for others?.', VALUE_DEFAULT, false),
1993 'gradeover' => new external_value(PARAM_ALPHANUMEXT, 'The new submission grade.', VALUE_DEFAULT, ''),
2000 * Evaluates a submission (used by teachers for provide feedback or override the submission grade).
2002 * @param int $submissionid the submission id
2003 * @param str $feedbacktext the feedback for the author
2004 * @param int $feedbackformat the feedback format for the reviewer text
2005 * @param bool $published whether to publish the submission for other users
2006 * @param mixed $gradeover the new submission grade (empty for no overriding the grade)
2007 * @return array containing the status and warnings.
2009 * @throws moodle_exception
2011 public static function evaluate_submission($submissionid, $feedbacktext = '', $feedbackformat = FORMAT_MOODLE, $published = 1,
2015 $params = self::validate_parameters(
2016 self::evaluate_submission_parameters(),
2018 'submissionid' => $submissionid,
2019 'feedbacktext' => $feedbacktext,
2020 'feedbackformat' => $feedbackformat,
2021 'published' => $published,
2022 'gradeover' => $gradeover,
2025 $warnings = array();
2027 // Get and validate the submission, submission and workshop.
2028 $submission = $DB->get_record('workshop_submissions', array('id' => $params['submissionid']), '*', MUST_EXIST);
2029 list($workshop, $course, $cm, $context) = self::validate_workshop($submission->workshopid);
2031 // Check we can evaluate the submission.
2032 self::validate_submission($submission, $workshop);
2033 $canpublish = has_capability('mod/workshop:publishsubmissions', $context);
2034 $canoverride = ($workshop->phase == workshop::PHASE_EVALUATION &&
2035 has_capability('mod/workshop:overridegrades', $context));
2037 if (!$canpublish && !$canoverride) {
2038 throw new moodle_exception('nopermissions', 'error', '', 'evaluate submission');
2042 $data = new stdClass;
2043 $data->id = $submission->id;
2044 $data->feedbackauthor_editor = array(
2045 'text' => $params['feedbacktext'],
2046 'format' => $params['feedbackformat'],
2048 $data->published = $params['published'];
2049 $data->gradeover = $params['gradeover'];
2053 'editablepublished' => $canpublish,
2054 'overridablegrade' => $canoverride
2056 $feedbackform = $workshop->get_feedbackauthor_form(null, $submission, $options);
2058 $errors = $feedbackform->validation((array) $data, array());
2059 // We can get several errors, return them in warnings.
2060 if (!empty($errors)) {
2062 foreach ($errors as $itemname => $message) {
2063 $warnings[] = array(
2064 'item' => $itemname,
2066 'warningcode' => 'fielderror',
2067 'message' => s($message)
2071 $workshop->evaluate_submission($submission, $data, $canpublish, $canoverride);
2076 'status' => $status,
2077 'warnings' => $warnings,
2082 * Returns description of method result value
2084 * @return external_description
2087 public static function evaluate_submission_returns() {
2088 return new external_single_structure(
2090 'status' => new external_value(PARAM_BOOL, 'status: true if the submission was evaluated, false otherwise.'),
2091 'warnings' => new external_warnings()