See Release Notes
Long Term Support Release
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>.< /** < * Feedback external API < * < * @package mod_feedback < * @category external < * @copyright 2017 Juan Leyva <juan@moodle.com> < * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later < * @since Moodle 3.3 < */ < < defined('MOODLE_INTERNAL') || die; < < require_once("$CFG->libdir/externallib.php"); <use mod_feedback\external\feedback_summary_exporter; use mod_feedback\external\feedback_completedtmp_exporter; use mod_feedback\external\feedback_item_exporter; use mod_feedback\external\feedback_valuetmp_exporter; use mod_feedback\external\feedback_value_exporter; use mod_feedback\external\feedback_completed_exporter;> use core_external\external_api; > use core_external\external_function_parameters; /** > use core_external\external_multiple_structure; * Feedback external functions > use core_external\external_single_structure; * > use core_external\external_value; * @package mod_feedback > use core_external\external_warnings; * @category external > use core_external\util;* @copyright 2017 Juan Leyva <juan@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 3.3 */ class mod_feedback_external extends external_api { /** * Describes the parameters for get_feedbacks_by_courses. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_feedbacks_by_courses_parameters() { return new external_function_parameters ( array( 'courseids' => new external_multiple_structure( new external_value(PARAM_INT, 'Course id'), 'Array of course ids', VALUE_DEFAULT, array() ), ) ); } /** * Returns a list of feedbacks in a provided list of courses. * If no list is provided all feedbacks that the user can view will be returned. * * @param array $courseids course ids * @return array of warnings and feedbacks * @since Moodle 3.3 */ public static function get_feedbacks_by_courses($courseids = array()) { global $PAGE; $warnings = array(); $returnedfeedbacks = array(); $params = array( 'courseids' => $courseids, ); $params = self::validate_parameters(self::get_feedbacks_by_courses_parameters(), $params); $mycourses = array(); if (empty($params['courseids'])) { $mycourses = enrol_get_my_courses(); $params['courseids'] = array_keys($mycourses); } // Ensure there are courseids to loop through. if (!empty($params['courseids'])) {< list($courses, $warnings) = external_util::validate_courses($params['courseids'], $mycourses);> list($courses, $warnings) = util::validate_courses($params['courseids'], $mycourses);$output = $PAGE->get_renderer('core'); // Get the feedbacks in this course, this function checks users visibility permissions. // We can avoid then additional validate_context calls. $feedbacks = get_all_instances_in_courses("feedback", $courses); foreach ($feedbacks as $feedback) { $context = context_module::instance($feedback->coursemodule); // Remove fields that are not from the feedback (added by get_all_instances_in_courses). unset($feedback->coursemodule, $feedback->context, $feedback->visible, $feedback->section, $feedback->groupmode, $feedback->groupingid); // Check permissions. if (!has_capability('mod/feedback:edititems', $context)) { // Don't return the optional properties. $properties = feedback_summary_exporter::properties_definition(); foreach ($properties as $property => $config) { if (!empty($config['optional'])) { unset($feedback->{$property}); } } } $exporter = new feedback_summary_exporter($feedback, array('context' => $context)); $returnedfeedbacks[] = $exporter->export($output); } } $result = array( 'feedbacks' => $returnedfeedbacks, 'warnings' => $warnings ); return $result; } /** * Describes the get_feedbacks_by_courses return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_feedbacks_by_courses_returns() { return new external_single_structure( array( 'feedbacks' => new external_multiple_structure( feedback_summary_exporter::get_read_structure() ), 'warnings' => new external_warnings(), ) ); } /** * Utility function for validating a feedback. * * @param int $feedbackid feedback instance id * @param int $courseid courseid course where user completes the feedback (for site feedbacks only) * @return array containing the feedback, feedback course, context, course module and the course where is being completed. * @throws moodle_exception * @since Moodle 3.3 */ protected static function validate_feedback($feedbackid, $courseid = 0) { global $DB, $USER; // Request and permission validation. $feedback = $DB->get_record('feedback', array('id' => $feedbackid), '*', MUST_EXIST); list($feedbackcourse, $cm) = get_course_and_cm_from_instance($feedback, 'feedback'); $context = context_module::instance($cm->id); self::validate_context($context); // Set default completion course. $completioncourse = (object) array('id' => 0); if ($feedbackcourse->id == SITEID && $courseid) { $completioncourse = get_course($courseid); self::validate_context(context_course::instance($courseid)); $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $courseid); if (!$feedbackcompletion->check_course_is_mapped()) { throw new moodle_exception('cannotaccess', 'mod_feedback'); } } return array($feedback, $feedbackcourse, $cm, $context, $completioncourse); } /** * Utility function for validating access to feedback. * * @param stdClass $feedback feedback object * @param stdClass $course course where user completes the feedback (for site feedbacks only) * @param stdClass $cm course module * @param stdClass $context context object * @throws moodle_exception * @return mod_feedback_completion feedback completion instance * @since Moodle 3.3 */ protected static function validate_feedback_access($feedback, $course, $cm, $context, $checksubmit = false) { $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $course->id); if (!$feedbackcompletion->can_complete()) { throw new required_capability_exception($context, 'mod/feedback:complete', 'nopermission', ''); } if (!$feedbackcompletion->is_open()) { throw new moodle_exception('feedback_is_not_open', 'feedback'); } if ($feedbackcompletion->is_empty()) { throw new moodle_exception('no_items_available_yet', 'feedback'); } if ($checksubmit && !$feedbackcompletion->can_submit()) { throw new moodle_exception('this_feedback_is_already_submitted', 'feedback'); } return $feedbackcompletion; } /** * Describes the parameters for get_feedback_access_information. * * @return external_external_function_parameters * @since Moodle 3.3 */ public static function get_feedback_access_information_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Return access information for a given feedback. * * @param int $feedbackid feedback instance id * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and the access information * @since Moodle 3.3 * @throws moodle_exception */ public static function get_feedback_access_information($feedbackid, $courseid = 0) { global $PAGE; $params = array( 'feedbackid' => $feedbackid, 'courseid' => $courseid, ); $params = self::validate_parameters(self::get_feedback_access_information_parameters(), $params); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id); $result = array(); // Capabilities first. $result['canviewanalysis'] = $feedbackcompletion->can_view_analysis(); $result['cancomplete'] = $feedbackcompletion->can_complete(); $result['cansubmit'] = $feedbackcompletion->can_submit(); $result['candeletesubmissions'] = has_capability('mod/feedback:deletesubmissions', $context); $result['canviewreports'] = has_capability('mod/feedback:viewreports', $context); $result['canedititems'] = has_capability('mod/feedback:edititems', $context); // Status information. $result['isempty'] = $feedbackcompletion->is_empty(); $result['isopen'] = $feedbackcompletion->is_open(); $anycourse = ($course->id == SITEID); $result['isalreadysubmitted'] = $feedbackcompletion->is_already_submitted($anycourse); $result['isanonymous'] = $feedbackcompletion->is_anonymous(); $result['warnings'] = []; return $result; } /** * Describes the get_feedback_access_information return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_feedback_access_information_returns() { return new external_single_structure( array( 'canviewanalysis' => new external_value(PARAM_BOOL, 'Whether the user can view the analysis or not.'), 'cancomplete' => new external_value(PARAM_BOOL, 'Whether the user can complete the feedback or not.'), 'cansubmit' => new external_value(PARAM_BOOL, 'Whether the user can submit the feedback or not.'), 'candeletesubmissions' => new external_value(PARAM_BOOL, 'Whether the user can delete submissions or not.'), 'canviewreports' => new external_value(PARAM_BOOL, 'Whether the user can view the feedback reports or not.'), 'canedititems' => new external_value(PARAM_BOOL, 'Whether the user can edit feedback items or not.'), 'isempty' => new external_value(PARAM_BOOL, 'Whether the feedback has questions or not.'), 'isopen' => new external_value(PARAM_BOOL, 'Whether the feedback has active access time restrictions or not.'), 'isalreadysubmitted' => new external_value(PARAM_BOOL, 'Whether the feedback is already submitted or not.'), 'isanonymous' => new external_value(PARAM_BOOL, 'Whether the feedback is anonymous or not.'), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for view_feedback. * * @return external_function_parameters * @since Moodle 3.3 */ public static function view_feedback_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'moduleviewed' => new external_value(PARAM_BOOL, 'If we need to mark the module as viewed for completion', VALUE_DEFAULT, false), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Trigger the course module viewed event and update the module completion status. * * @param int $feedbackid feedback instance id * @param bool $moduleviewed If we need to mark the module as viewed for completion * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and status result * @since Moodle 3.3 * @throws moodle_exception */ public static function view_feedback($feedbackid, $moduleviewed = false, $courseid = 0) { $params = array('feedbackid' => $feedbackid, 'moduleviewed' => $moduleviewed, 'courseid' => $courseid); $params = self::validate_parameters(self::view_feedback_parameters(), $params); $warnings = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id); // Trigger module viewed event. $feedbackcompletion->trigger_module_viewed(); if ($params['moduleviewed']) { if (!$feedbackcompletion->is_open()) { throw new moodle_exception('feedback_is_not_open', 'feedback'); } // Mark activity viewed for completion-tracking. $feedbackcompletion->set_module_viewed(); } $result = array( 'status' => true, 'warnings' => $warnings, ); return $result; } /** * Describes the view_feedback return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function view_feedback_returns() { return new external_single_structure( array( 'status' => new external_value(PARAM_BOOL, 'status: true if success'), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_current_completed_tmp. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_current_completed_tmp_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Returns the temporary completion record for the current user. * * @param int $feedbackid feedback instance id * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and status result * @since Moodle 3.3 * @throws moodle_exception */ public static function get_current_completed_tmp($feedbackid, $courseid = 0) { global $PAGE; $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid); $params = self::validate_parameters(self::get_current_completed_tmp_parameters(), $params); $warnings = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id); if ($completed = $feedbackcompletion->get_current_completed_tmp()) { $exporter = new feedback_completedtmp_exporter($completed); return array( 'feedback' => $exporter->export($PAGE->get_renderer('core')), 'warnings' => $warnings, ); } throw new moodle_exception('not_started', 'feedback'); } /** * Describes the get_current_completed_tmp return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_current_completed_tmp_returns() { return new external_single_structure( array( 'feedback' => feedback_completedtmp_exporter::get_read_structure(), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_items. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_items_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Returns the items (questions) in the given feedback. * * @param int $feedbackid feedback instance id * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and feedbacks * @since Moodle 3.3 */ public static function get_items($feedbackid, $courseid = 0) { global $PAGE; $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid); $params = self::validate_parameters(self::get_items_parameters(), $params); $warnings = array();> $returneditems = array();list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']);> $userhasaccess = true; $feedbackstructure = new mod_feedback_structure($feedback, $cm, $completioncourse->id); > try { $returneditems = array(); > // Check the user has access to the feedback. if ($items = $feedbackstructure->get_items()) { > self::validate_feedback_access($feedback, $completioncourse, $cm, $context, true); foreach ($items as $item) { > } catch (moodle_exception $e) { $itemnumber = empty($item->itemnr) ? null : $item->itemnr; > $userhasaccess = false; unset($item->itemnr); // Added by the function, not part of the record. > $warnings[] = [ $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber)); > 'item' => $feedback->id, $returneditems[] = $exporter->export($PAGE->get_renderer('core')); > 'warningcode' => clean_param($e->errorcode, PARAM_ALPHANUM), } > 'message' => $e->getMessage(), } > ]; > } $result = array( > 'items' => $returneditems, > // For consistency with the web behaviour, the items should be returned only when the user can edit or view reports (to 'warnings' => $warnings > // include non-editing teachers too). ); > $capabilities = [ return $result; > 'mod/feedback:edititems', } > 'mod/feedback:viewreports', > ]; /** > if ($userhasaccess || has_any_capability($capabilities, $context)) { * Describes the get_items return value. > // Remove previous warnings because, although the user might not have access, they have the proper capability. * > $warnings = [];< $returneditems = array();* @since Moodle 3.3> } else if ($userhasaccess) { */ > $warnings[] = [ public static function get_items_returns() { > 'item' => $feedback->id, return new external_single_structure( > 'warningcode' => 'nopermission', array( > 'message' => 'nopermission', 'items' => new external_multiple_structure( > ]; feedback_item_exporter::get_read_structure() > }), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for launch_feedback. * * @return external_function_parameters * @since Moodle 3.3 */ public static function launch_feedback_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Starts or continues a feedback submission * * @param array $feedbackid feedback instance id * @param int $courseid course where user completes a feedback (for site feedbacks only). * @return array of warnings and launch information * @since Moodle 3.3 */ public static function launch_feedback($feedbackid, $courseid = 0) { global $PAGE; $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid); $params = self::validate_parameters(self::launch_feedback_parameters(), $params); $warnings = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); // Check we can do a new submission (or continue an existing). $feedbackcompletion = self::validate_feedback_access($feedback, $completioncourse, $cm, $context, true); $gopage = $feedbackcompletion->get_resume_page(); if ($gopage === null) { $gopage = -1; // Last page. } $result = array( 'gopage' => $gopage, 'warnings' => $warnings ); return $result; } /** * Describes the launch_feedback return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function launch_feedback_returns() { return new external_single_structure( array( 'gopage' => new external_value(PARAM_INT, 'The next page to go (-1 if we were already in the last page). 0 for first page.'), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_page_items. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_page_items_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'page' => new external_value(PARAM_INT, 'The page to get starting by 0'), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Get a single feedback page items. * * @param int $feedbackid feedback instance id * @param int $page the page to get starting by 0 * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and launch information * @since Moodle 3.3 */ public static function get_page_items($feedbackid, $page, $courseid = 0) { global $PAGE; $params = array('feedbackid' => $feedbackid, 'page' => $page, 'courseid' => $courseid); $params = self::validate_parameters(self::get_page_items_parameters(), $params); $warnings = array();> $returneditems = array(); > $hasprevpage = false; list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], > $hasnextpage = false;$params['courseid']);> $userhasaccess = true; $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id); > $feedbackcompletion = null; > try { $page = $params['page']; > // Check the user has access to the feedback. $pages = $feedbackcompletion->get_pages(); > $feedbackcompletion = self::validate_feedback_access($feedback, $completioncourse, $cm, $context, true); $pageitems = $pages[$page]; > } catch (moodle_exception $e) { $hasnextpage = $page < count($pages) - 1; // Until we complete this page we can not trust get_next_page(). > $userhasaccess = false; $hasprevpage = $page && ($feedbackcompletion->get_previous_page($page, false) !== null); > $warnings[] = [ > 'item' => $feedback->id, $returneditems = array(); > 'warningcode' => str_replace('_', '', $e->errorcode), foreach ($pageitems as $item) { > 'message' => $e->getMessage(), $itemnumber = empty($item->itemnr) ? null : $item->itemnr; > ]; unset($item->itemnr); // Added by the function, not part of the record. > } $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber)); > $returneditems[] = $exporter->export($PAGE->get_renderer('core')); > // For consistency with the web behaviour, the items should be returned only when the user can edit or view reports (to } > // include non-editing teachers too). > $capabilities = [ $result = array( > 'mod/feedback:edititems', 'items' => $returneditems, > 'mod/feedback:viewreports', 'hasprevpage' => $hasprevpage, > ]; 'hasnextpage' => $hasnextpage, > if ($userhasaccess || has_any_capability($capabilities, $context)) { 'warnings' => $warnings > // Remove previous warnings because, although the user might not have access, they have the proper capability. ); > $warnings = []; return $result; > } > if ($feedbackcompletion == null) {> }< $returneditems = array();* Describes the get_page_items return value.> } * > } else if ($userhasaccess) { * @return external_single_structure > $warnings[] = [ * @since Moodle 3.3 > 'item' => $feedback->id, */ > 'warningcode' => 'nopermission', public static function get_page_items_returns() { > 'message' => get_string('nopermission', 'mod_feedback'), return new external_single_structure( > ];array( 'items' => new external_multiple_structure( feedback_item_exporter::get_read_structure() ), 'hasprevpage' => new external_value(PARAM_BOOL, 'Whether is a previous page.'), 'hasnextpage' => new external_value(PARAM_BOOL, 'Whether there are more pages.'), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for process_page. * * @return external_function_parameters * @since Moodle 3.3 */ public static function process_page_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'), 'page' => new external_value(PARAM_INT, 'The page being processed.'), 'responses' => new external_multiple_structure( new external_single_structure( array( 'name' => new external_value(PARAM_NOTAGS, 'The response name (usually type[index]_id).'), 'value' => new external_value(PARAM_RAW, 'The response value.'), ) ), 'The data to be processed.', VALUE_DEFAULT, array() ), 'goprevious' => new external_value(PARAM_BOOL, 'Whether we want to jump to previous page.', VALUE_DEFAULT, false), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Process a jump between pages. * * @param array $feedbackid feedback instance id * @param array $page the page being processed * @param array $responses the responses to be processed * @param bool $goprevious whether we want to jump to previous page * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and launch information * @since Moodle 3.3 */ public static function process_page($feedbackid, $page, $responses = [], $goprevious = false, $courseid = 0) { global $USER, $SESSION; $params = array('feedbackid' => $feedbackid, 'page' => $page, 'responses' => $responses, 'goprevious' => $goprevious, 'courseid' => $courseid); $params = self::validate_parameters(self::process_page_parameters(), $params); $warnings = array(); $siteaftersubmit = $completionpagecontents = ''; list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); // Check we can do a new submission (or continue an existing). $feedbackcompletion = self::validate_feedback_access($feedback, $completioncourse, $cm, $context, true); // Create the $_POST object required by the feedback question engine. $_POST = array(); foreach ($responses as $response) { // First check if we are handling array parameters. if (preg_match('/(.+)\[(.+)\]$/', $response['name'], $matches)) { $_POST[$matches[1]][$matches[2]] = $response['value']; } else { $_POST[$response['name']] = $response['value']; } } // Force fields. $_POST['id'] = $cm->id; $_POST['courseid'] = $courseid; $_POST['gopage'] = $params['page']; $_POST['_qf__mod_feedback_complete_form'] = 1; // Determine where to go, backwards or forward. if (!$params['goprevious']) { $_POST['gonextpage'] = 1; // Even if we are saving values we need this set. if ($feedbackcompletion->get_next_page($params['page'], false) === null) { $_POST['savevalues'] = 1; // If there is no next page, it means we are finishing the feedback. } } // Ignore sesskey (deep in some APIs), the request is already validated. $USER->ignoresesskey = true; feedback_init_feedback_session(); $SESSION->feedback->is_started = true; $feedbackcompletion->process_page($params['page'], $params['goprevious']); $completed = $feedbackcompletion->just_completed(); if ($completed) { $jumpto = 0; if ($feedback->page_after_submit) { $completionpagecontents = $feedbackcompletion->page_after_submit(); } if ($feedback->site_after_submit) { $siteaftersubmit = feedback_encode_target_url($feedback->site_after_submit); } } else { $jumpto = $feedbackcompletion->get_jumpto(); } $result = array( 'jumpto' => $jumpto, 'completed' => $completed, 'completionpagecontents' => $completionpagecontents, 'siteaftersubmit' => $siteaftersubmit, 'warnings' => $warnings ); return $result; } /** * Describes the process_page return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function process_page_returns() { return new external_single_structure( array( 'jumpto' => new external_value(PARAM_INT, 'The page to jump to.'), 'completed' => new external_value(PARAM_BOOL, 'If the user completed the feedback.'), 'completionpagecontents' => new external_value(PARAM_RAW, 'The completion page contents.'), 'siteaftersubmit' => new external_value(PARAM_RAW, 'The link (could be relative) to show after submit.'), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_analysis. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_analysis_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group', VALUE_DEFAULT, 0), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Retrieves the feedback analysis. * * @param array $feedbackid feedback instance id * @param int $groupid group id, 0 means that the function will determine the user group * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and launch information * @since Moodle 3.3 */ public static function get_analysis($feedbackid, $groupid = 0, $courseid = 0) { global $PAGE; $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid, 'courseid' => $courseid); $params = self::validate_parameters(self::get_analysis_parameters(), $params); $warnings = $itemsdata = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); // Check permissions. $feedbackstructure = new mod_feedback_structure($feedback, $cm, $completioncourse->id); if (!$feedbackstructure->can_view_analysis()) { throw new required_capability_exception($context, 'mod/feedback:viewanalysepage', 'nopermission', ''); } if (!empty($params['groupid'])) { $groupid = $params['groupid']; // Determine is the group is visible to user. if (!groups_group_visible($groupid, $course, $cm)) { throw new moodle_exception('notingroup'); } } else { // Check to see if groups are being used here. if ($groupmode = groups_get_activity_groupmode($cm)) { $groupid = groups_get_activity_group($cm); // Determine is the group is visible to user (this is particullary for the group 0 -> all groups). if (!groups_group_visible($groupid, $course, $cm)) { throw new moodle_exception('notingroup'); } } else { $groupid = 0; } } // Summary data. $summary = new mod_feedback\output\summary($feedbackstructure, $groupid); $summarydata = $summary->export_for_template($PAGE->get_renderer('core')); $checkanonymously = true; if ($groupid > 0 AND $feedback->anonymous == FEEDBACK_ANONYMOUS_YES) { $completedcount = $feedbackstructure->count_completed_responses($groupid); if ($completedcount < FEEDBACK_MIN_ANONYMOUS_COUNT_IN_GROUP) { $checkanonymously = false; } } if ($checkanonymously) { // Get the items of the feedback. $items = $feedbackstructure->get_items(true); foreach ($items as $item) { $itemobj = feedback_get_item_class($item->typ); $itemnumber = empty($item->itemnr) ? null : $item->itemnr; unset($item->itemnr); // Added by the function, not part of the record. $exporter = new feedback_item_exporter($item, array('context' => $context, 'itemnumber' => $itemnumber)); $itemsdata[] = array( 'item' => $exporter->export($PAGE->get_renderer('core')), 'data' => $itemobj->get_analysed_for_external($item, $groupid), ); } } else { $warnings[] = array( 'item' => 'feedback', 'itemid' => $feedback->id, 'warningcode' => 'insufficientresponsesforthisgroup', 'message' => s(get_string('insufficient_responses_for_this_group', 'feedback')) ); } $result = array( 'completedcount' => $summarydata->completedcount, 'itemscount' => $summarydata->itemscount, 'itemsdata' => $itemsdata, 'warnings' => $warnings ); return $result; } /** * Describes the get_analysis return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_analysis_returns() { return new external_single_structure( array( 'completedcount' => new external_value(PARAM_INT, 'Number of completed submissions.'), 'itemscount' => new external_value(PARAM_INT, 'Number of items (questions).'), 'itemsdata' => new external_multiple_structure( new external_single_structure( array( 'item' => feedback_item_exporter::get_read_structure(), 'data' => new external_multiple_structure( new external_value(PARAM_RAW, 'The analysis data (can be json encoded)') ), ) ) ), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_unfinished_responses. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_unfinished_responses_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Retrieves responses from the current unfinished attempt. * * @param array $feedbackid feedback instance id * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and launch information * @since Moodle 3.3 */ public static function get_unfinished_responses($feedbackid, $courseid = 0) { global $PAGE; $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid); $params = self::validate_parameters(self::get_unfinished_responses_parameters(), $params); $warnings = $itemsdata = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id); $responses = array(); $unfinished = $feedbackcompletion->get_unfinished_responses(); foreach ($unfinished as $u) { $exporter = new feedback_valuetmp_exporter($u); $responses[] = $exporter->export($PAGE->get_renderer('core')); } $result = array( 'responses' => $responses, 'warnings' => $warnings ); return $result; } /** * Describes the get_unfinished_responses return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_unfinished_responses_returns() { return new external_single_structure( array( 'responses' => new external_multiple_structure( feedback_valuetmp_exporter::get_read_structure() ), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_finished_responses. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_finished_responses_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id.'), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Retrieves responses from the last finished attempt. * * @param array $feedbackid feedback instance id * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and the responses * @since Moodle 3.3 */ public static function get_finished_responses($feedbackid, $courseid = 0) { global $PAGE; $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid); $params = self::validate_parameters(self::get_finished_responses_parameters(), $params); $warnings = $itemsdata = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id); $responses = array(); // Load and get the responses from the last completed feedback. $feedbackcompletion->find_last_completed(); $unfinished = $feedbackcompletion->get_finished_responses(); foreach ($unfinished as $u) { $exporter = new feedback_value_exporter($u); $responses[] = $exporter->export($PAGE->get_renderer('core')); } $result = array( 'responses' => $responses, 'warnings' => $warnings ); return $result; } /** * Describes the get_finished_responses return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_finished_responses_returns() { return new external_single_structure( array( 'responses' => new external_multiple_structure( feedback_value_exporter::get_read_structure() ), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_non_respondents. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_non_respondents_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.', VALUE_DEFAULT, 0), 'sort' => new external_value(PARAM_ALPHA, 'Sort param, must be firstname, lastname or lastaccess (default).', VALUE_DEFAULT, 'lastaccess'), 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0), 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page.', VALUE_DEFAULT, 0), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Retrieves a list of students who didn't submit the feedback. * * @param int $feedbackid feedback instance id * @param int $groupid Group id, 0 means that the function will determine the user group' * @param str $sort sort param, must be firstname, lastname or lastaccess (default) * @param int $page the page of records to return * @param int $perpage the number of records to return per page * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and users ids * @since Moodle 3.3 */ public static function get_non_respondents($feedbackid, $groupid = 0, $sort = 'lastaccess', $page = 0, $perpage = 0, $courseid = 0) { global $CFG; require_once($CFG->dirroot . '/mod/feedback/lib.php'); $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid, 'sort' => $sort, 'page' => $page, 'perpage' => $perpage, 'courseid' => $courseid); $params = self::validate_parameters(self::get_non_respondents_parameters(), $params); $warnings = $nonrespondents = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id); $completioncourseid = $feedbackcompletion->get_courseid(); if ($feedback->anonymous != FEEDBACK_ANONYMOUS_NO || $feedback->course == SITEID) { throw new moodle_exception('anonymous', 'feedback'); } // Check permissions. require_capability('mod/feedback:viewreports', $context); if (!empty($params['groupid'])) { $groupid = $params['groupid']; // Determine is the group is visible to user. if (!groups_group_visible($groupid, $course, $cm)) { throw new moodle_exception('notingroup'); } } else { // Check to see if groups are being used here. if ($groupmode = groups_get_activity_groupmode($cm)) { $groupid = groups_get_activity_group($cm); // Determine is the group is visible to user (this is particullary for the group 0 -> all groups). if (!groups_group_visible($groupid, $course, $cm)) { throw new moodle_exception('notingroup'); } } else { $groupid = 0; } } if ($params['sort'] !== 'firstname' && $params['sort'] !== 'lastname' && $params['sort'] !== 'lastaccess') { throw new invalid_parameter_exception('Invalid sort param, must be firstname, lastname or lastaccess.'); } // Check if we are page filtering. if ($params['perpage'] == 0) { $page = $params['page']; $perpage = FEEDBACK_DEFAULT_PAGE_COUNT; } else { $perpage = $params['perpage']; $page = $perpage * $params['page']; } $users = feedback_get_incomplete_users($cm, $groupid, $params['sort'], $page, $perpage, true); foreach ($users as $user) { $nonrespondents[] = [ 'courseid' => $completioncourseid, 'userid' => $user->id, 'fullname' => fullname($user), 'started' => $user->feedbackstarted ]; } $result = array( 'users' => $nonrespondents, 'total' => feedback_count_incomplete_users($cm, $groupid), 'warnings' => $warnings ); return $result; } /** * Describes the get_non_respondents return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_non_respondents_returns() { return new external_single_structure( array( 'users' => new external_multiple_structure( new external_single_structure( array( 'courseid' => new external_value(PARAM_INT, 'Course id'), 'userid' => new external_value(PARAM_INT, 'The user id'), 'fullname' => new external_value(PARAM_TEXT, 'User full name'), 'started' => new external_value(PARAM_BOOL, 'If the user has started the attempt'), ) ) ), 'total' => new external_value(PARAM_INT, 'Total number of non respondents'), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_responses_analysis. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_responses_analysis_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group', VALUE_DEFAULT, 0), 'page' => new external_value(PARAM_INT, 'The page of records to return.', VALUE_DEFAULT, 0), 'perpage' => new external_value(PARAM_INT, 'The number of records to return per page', VALUE_DEFAULT, 0), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Return the feedback user responses. * * @param int $feedbackid feedback instance id * @param int $groupid Group id, 0 means that the function will determine the user group * @param int $page the page of records to return * @param int $perpage the number of records to return per page * @param int $courseid course where user completes the feedback (for site feedbacks only) * @return array of warnings and users attemps and responses * @throws moodle_exception * @since Moodle 3.3 */ public static function get_responses_analysis($feedbackid, $groupid = 0, $page = 0, $perpage = 0, $courseid = 0) { $params = array('feedbackid' => $feedbackid, 'groupid' => $groupid, 'page' => $page, 'perpage' => $perpage, 'courseid' => $courseid); $params = self::validate_parameters(self::get_responses_analysis_parameters(), $params); $warnings = $itemsdata = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); // Check permissions. require_capability('mod/feedback:viewreports', $context); if (!empty($params['groupid'])) { $groupid = $params['groupid']; // Determine is the group is visible to user. if (!groups_group_visible($groupid, $course, $cm)) { throw new moodle_exception('notingroup'); } } else { // Check to see if groups are being used here. if ($groupmode = groups_get_activity_groupmode($cm)) { $groupid = groups_get_activity_group($cm); // Determine is the group is visible to user (this is particullary for the group 0 -> all groups). if (!groups_group_visible($groupid, $course, $cm)) { throw new moodle_exception('notingroup'); } } else { $groupid = 0; } } $feedbackstructure = new mod_feedback_structure($feedback, $cm, $completioncourse->id); $responsestable = new mod_feedback_responses_table($feedbackstructure, $groupid); // Ensure responses number is correct prior returning them. $feedbackstructure->shuffle_anonym_responses(); $anonresponsestable = new mod_feedback_responses_anon_table($feedbackstructure, $groupid); $result = array( 'attempts' => $responsestable->export_external_structure($params['page'], $params['perpage']), 'totalattempts' => $responsestable->get_total_responses_count(), 'anonattempts' => $anonresponsestable->export_external_structure($params['page'], $params['perpage']), 'totalanonattempts' => $anonresponsestable->get_total_responses_count(), 'warnings' => $warnings ); return $result; } /** * Describes the get_responses_analysis return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_responses_analysis_returns() { $responsestructure = new external_multiple_structure( new external_single_structure( array( 'id' => new external_value(PARAM_INT, 'Response id'), 'name' => new external_value(PARAM_RAW, 'Response name'), 'printval' => new external_value(PARAM_RAW, 'Response ready for output'), 'rawval' => new external_value(PARAM_RAW, 'Response raw value'), ) ) ); return new external_single_structure( array( 'attempts' => new external_multiple_structure( new external_single_structure( array( 'id' => new external_value(PARAM_INT, 'Completed id'), 'courseid' => new external_value(PARAM_INT, 'Course id'), 'userid' => new external_value(PARAM_INT, 'User who responded'), 'timemodified' => new external_value(PARAM_INT, 'Time modified for the response'), 'fullname' => new external_value(PARAM_TEXT, 'User full name'), 'responses' => $responsestructure ) ) ), 'totalattempts' => new external_value(PARAM_INT, 'Total responses count.'), 'anonattempts' => new external_multiple_structure( new external_single_structure( array( 'id' => new external_value(PARAM_INT, 'Completed id'), 'courseid' => new external_value(PARAM_INT, 'Course id'), 'number' => new external_value(PARAM_INT, 'Response number'), 'responses' => $responsestructure ) ) ), 'totalanonattempts' => new external_value(PARAM_INT, 'Total anonymous responses count.'), 'warnings' => new external_warnings(), ) ); } /** * Describes the parameters for get_last_completed. * * @return external_function_parameters * @since Moodle 3.3 */ public static function get_last_completed_parameters() { return new external_function_parameters ( array( 'feedbackid' => new external_value(PARAM_INT, 'Feedback instance id'), 'courseid' => new external_value(PARAM_INT, 'Course where user completes the feedback (for site feedbacks only).', VALUE_DEFAULT, 0), ) ); } /** * Retrieves the last completion record for the current user. * * @param int $feedbackid feedback instance id * @return array of warnings and the last completed record * @since Moodle 3.3 * @throws moodle_exception */ public static function get_last_completed($feedbackid, $courseid = 0) { global $PAGE; $params = array('feedbackid' => $feedbackid, 'courseid' => $courseid); $params = self::validate_parameters(self::get_last_completed_parameters(), $params); $warnings = array(); list($feedback, $course, $cm, $context, $completioncourse) = self::validate_feedback($params['feedbackid'], $params['courseid']); $feedbackcompletion = new mod_feedback_completion($feedback, $cm, $completioncourse->id); if ($feedbackcompletion->is_anonymous()) { throw new moodle_exception('anonymous', 'feedback'); } if ($completed = $feedbackcompletion->find_last_completed()) { $exporter = new feedback_completed_exporter($completed); return array( 'completed' => $exporter->export($PAGE->get_renderer('core')), 'warnings' => $warnings, ); } throw new moodle_exception('not_completed_yet', 'feedback'); } /** * Describes the get_last_completed return value. * * @return external_single_structure * @since Moodle 3.3 */ public static function get_last_completed_returns() { return new external_single_structure( array( 'completed' => feedback_completed_exporter::get_read_structure(), 'warnings' => new external_warnings(), ) ); } }