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 * Choice module external API
22 * @copyright 2015 Costantino Cito <ccito@cvaconsulting.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') || die;
28 require_once($CFG->libdir . '/externallib.php');
29 require_once($CFG->dirroot . '/mod/choice/lib.php');
32 * Choice module external functions
36 * @copyright 2015 Costantino Cito <ccito@cvaconsulting.com>
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class mod_choice_external extends external_api {
43 * Describes the parameters for get_choices_by_courses.
45 * @return external_external_function_parameters
48 public static function get_choice_results_parameters() {
49 return new external_function_parameters (array('choiceid' => new external_value(PARAM_INT, 'choice instance id')));
52 * Returns user's results for a specific choice
53 * and a list of those users that did not answered yet.
55 * @param int $choiceid the choice instance id
56 * @return array of responses details
59 public static function get_choice_results($choiceid) {
62 $params = self::validate_parameters(self::get_choice_results_parameters(), array('choiceid' => $choiceid));
64 if (!$choice = choice_get_choice($params['choiceid'])) {
65 throw new moodle_exception("invalidcoursemodule", "error");
67 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
69 $context = context_module::instance($cm->id);
70 self::validate_context($context);
72 $groupmode = groups_get_activity_groupmode($cm);
73 // Check if we have to include responses from inactive users.
74 $onlyactive = $choice->includeinactive ? false : true;
75 $users = choice_get_response_data($choice, $cm, $groupmode, $onlyactive);
76 // Show those who haven't answered the question.
77 if (!empty($choice->showunanswered)) {
78 $choice->option[0] = get_string('notanswered', 'choice');
79 $choice->maxanswers[0] = 0;
81 $results = prepare_choice_show_results($choice, $course, $cm, $users);
84 $fullnamecap = has_capability('moodle/site:viewfullnames', $context);
85 foreach ($results->options as $optionid => $option) {
87 $userresponses = array();
89 $percentageamount = 0;
90 if (property_exists($option, 'user') and
91 (has_capability('mod/choice:readresponses', $context) or choice_can_view_results($choice))) {
92 $numberofuser = count($option->user);
93 $percentageamount = ((float)$numberofuser / (float)$results->numberofuser) * 100.0;
94 if ($choice->publish) {
95 foreach ($option->user as $userresponse) {
97 $response['userid'] = $userresponse->id;
98 $response['fullname'] = fullname($userresponse, $fullnamecap);
99 $usercontext = context_user::instance($userresponse->id, IGNORE_MISSING);
101 $profileimageurl = moodle_url::make_webservice_pluginfile_url($usercontext->id, 'user', 'icon', null,
102 '/', 'f1')->out(false);
104 $profileimageurl = '';
106 $response['profileimageurl'] = $profileimageurl;
107 // Add optional properties.
108 foreach (array('answerid', 'timemodified') as $field) {
109 if (property_exists($userresponse, 'answerid')) {
110 $response[$field] = $userresponse->$field;
113 $userresponses[] = $response;
118 $options[] = array('id' => $optionid,
119 'text' => format_string($option->text, true, array('context' => $context)),
120 'maxanswer' => $option->maxanswer,
121 'userresponses' => $userresponses,
122 'numberofuser' => $numberofuser,
123 'percentageamount' => $percentageamount
129 'options' => $options,
130 'warnings' => $warnings
135 * Describes the get_choice_results return value.
137 * @return external_single_structure
140 public static function get_choice_results_returns() {
141 return new external_single_structure(
143 'options' => new external_multiple_structure(
144 new external_single_structure(
146 'id' => new external_value(PARAM_INT, 'choice instance id'),
147 'text' => new external_value(PARAM_RAW, 'text of the choice'),
148 'maxanswer' => new external_value(PARAM_INT, 'maximum number of answers'),
149 'userresponses' => new external_multiple_structure(
150 new external_single_structure(
152 'userid' => new external_value(PARAM_INT, 'user id'),
153 'fullname' => new external_value(PARAM_NOTAGS, 'user full name'),
154 'profileimageurl' => new external_value(PARAM_URL, 'profile user image url'),
155 'answerid' => new external_value(PARAM_INT, 'answer id', VALUE_OPTIONAL),
156 'timemodified' => new external_value(PARAM_INT, 'time of modification', VALUE_OPTIONAL),
160 'numberofuser' => new external_value(PARAM_INT, 'number of users answers'),
161 'percentageamount' => new external_value(PARAM_FLOAT, 'percentage of users answers')
165 'warnings' => new external_warnings(),
171 * Describes the parameters for mod_choice_get_choice_options.
173 * @return external_external_function_parameters
176 public static function get_choice_options_parameters() {
177 return new external_function_parameters (array('choiceid' => new external_value(PARAM_INT, 'choice instance id')));
181 * Returns options for a specific choice
183 * @param int $choiceid the choice instance id
184 * @return array of options details
187 public static function get_choice_options($choiceid) {
190 $params = self::validate_parameters(self::get_choice_options_parameters(), array('choiceid' => $choiceid));
192 if (!$choice = choice_get_choice($params['choiceid'])) {
193 throw new moodle_exception("invalidcoursemodule", "error");
195 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
197 $context = context_module::instance($cm->id);
198 self::validate_context($context);
200 require_capability('mod/choice:choose', $context);
202 $groupmode = groups_get_activity_groupmode($cm);
203 $onlyactive = $choice->includeinactive ? false : true;
204 $allresponses = choice_get_response_data($choice, $cm, $groupmode, $onlyactive);
208 $showpreview = false;
210 if ($choice->timeclose != 0) {
211 if ($choice->timeopen > $timenow) {
213 $warnings[1] = get_string("notopenyet", "choice", userdate($choice->timeopen));
214 if ($choice->showpreview) {
215 $warnings[2] = get_string('previewonly', 'choice', userdate($choice->timeopen));
219 if ($timenow > $choice->timeclose) {
221 $warnings[3] = get_string("expired", "choice", userdate($choice->timeclose));
224 $optionsarray = array();
226 if ($choiceopen or $showpreview) {
228 $options = choice_prepare_options($choice, $USER, $cm, $allresponses);
230 foreach ($options['options'] as $option) {
231 $optionarr = array();
232 $optionarr['id'] = $option->attributes->value;
233 $optionarr['text'] = format_string($option->text, true, array('context' => $context));
234 $optionarr['maxanswers'] = $option->maxanswers;
235 $optionarr['displaylayout'] = $option->displaylayout;
236 $optionarr['countanswers'] = $option->countanswers;
237 foreach (array('checked', 'disabled') as $field) {
238 if (property_exists($option->attributes, $field) and $option->attributes->$field == 1) {
239 $optionarr[$field] = 1;
241 $optionarr[$field] = 0;
244 // When showpreview is active, we show options as disabled.
245 if ($showpreview or ($optionarr['checked'] == 1 and !$choice->allowupdate)) {
246 $optionarr['disabled'] = 1;
248 $optionsarray[] = $optionarr;
251 foreach ($warnings as $key => $message) {
252 $warnings[$key] = array(
255 'warningcode' => $key,
256 'message' => $message
260 'options' => $optionsarray,
261 'warnings' => $warnings
266 * Describes the get_choice_results return value.
268 * @return external_multiple_structure
271 public static function get_choice_options_returns() {
272 return new external_single_structure(
274 'options' => new external_multiple_structure(
275 new external_single_structure(
277 'id' => new external_value(PARAM_INT, 'option id'),
278 'text' => new external_value(PARAM_RAW, 'text of the choice'),
279 'maxanswers' => new external_value(PARAM_INT, 'maximum number of answers'),
280 'displaylayout' => new external_value(PARAM_BOOL, 'true for orizontal, otherwise vertical'),
281 'countanswers' => new external_value(PARAM_INT, 'number of answers'),
282 'checked' => new external_value(PARAM_BOOL, 'we already answered'),
283 'disabled' => new external_value(PARAM_BOOL, 'option disabled'),
287 'warnings' => new external_warnings(),
293 * Describes the parameters for submit_choice_response.
295 * @return external_external_function_parameters
298 public static function submit_choice_response_parameters() {
299 return new external_function_parameters (
301 'choiceid' => new external_value(PARAM_INT, 'choice instance id'),
302 'responses' => new external_multiple_structure(
303 new external_value(PARAM_INT, 'answer id'),
304 'Array of response ids'
311 * Submit choice responses
313 * @param int $choiceid the choice instance id
314 * @param array $responses the response ids
315 * @return array ansers informatinon and warnings
318 public static function submit_choice_response($choiceid, $responses) {
322 $params = self::validate_parameters(self::submit_choice_response_parameters(),
324 'choiceid' => $choiceid,
325 'responses' => $responses
328 if (!$choice = choice_get_choice($params['choiceid'])) {
329 throw new moodle_exception("invalidcoursemodule", "error");
331 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
333 $context = context_module::instance($cm->id);
334 self::validate_context($context);
336 require_capability('mod/choice:choose', $context);
339 if ($choice->timeclose != 0) {
340 if ($choice->timeopen > $timenow) {
341 throw new moodle_exception("notopenyet", "choice", '', userdate($choice->timeopen));
342 } else if ($timenow > $choice->timeclose) {
343 throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose));
346 if (!choice_get_my_response($choice) or $choice->allowupdate) {
347 // When a single response is given, we convert the array to a simple variable
348 // in order to avoid choice_user_submit_response to check with allowmultiple even
349 // for a single response.
350 if (count($params['responses']) == 1) {
351 $params['responses'] = reset($params['responses']);
353 choice_user_submit_response($params['responses'], $choice, $USER->id, $course, $cm);
355 throw new moodle_exception('missingrequiredcapability', 'webservice', '', 'allowupdate');
357 $answers = choice_get_my_response($choice);
360 'answers' => $answers,
361 'warnings' => $warnings
366 * Describes the submit_choice_response return value.
368 * @return external_multiple_structure
371 public static function submit_choice_response_returns() {
372 return new external_single_structure(
374 'answers' => new external_multiple_structure(
375 new external_single_structure(
377 'id' => new external_value(PARAM_INT, 'answer id'),
378 'choiceid' => new external_value(PARAM_INT, 'choiceid'),
379 'userid' => new external_value(PARAM_INT, 'user id'),
380 'optionid' => new external_value(PARAM_INT, 'optionid'),
381 'timemodified' => new external_value(PARAM_INT, 'time of last modification')
385 'warnings' => new external_warnings(),
391 * Returns description of method parameters
393 * @return external_function_parameters
396 public static function view_choice_parameters() {
397 return new external_function_parameters(
399 'choiceid' => new external_value(PARAM_INT, 'choice instance id')
405 * Trigger the course module viewed event and update the module completion status.
407 * @param int $choiceid the choice instance id
408 * @return array of warnings and status result
410 * @throws moodle_exception
412 public static function view_choice($choiceid) {
415 $params = self::validate_parameters(self::view_choice_parameters(),
417 'choiceid' => $choiceid
421 // Request and permission validation.
422 if (!$choice = choice_get_choice($params['choiceid'])) {
423 throw new moodle_exception("invalidcoursemodule", "error");
425 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
427 $context = context_module::instance($cm->id);
428 self::validate_context($context);
430 // Trigger course_module_viewed event and completion.
431 choice_view($choice, $course, $cm, $context);
434 $result['status'] = true;
435 $result['warnings'] = $warnings;
440 * Returns description of method result value
442 * @return external_description
445 public static function view_choice_returns() {
446 return new external_single_structure(
448 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
449 'warnings' => new external_warnings()