MDL-51566 mod_choice: New WS mod_choice_delete_choice_responses
[moodle.git] / mod / choice / classes / external.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Choice module external API
19  *
20  * @package    mod_choice
21  * @category   external
22  * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  * @since      Moodle 3.0
25  */
27 defined('MOODLE_INTERNAL') || die;
28 require_once($CFG->libdir . '/externallib.php');
29 require_once($CFG->dirroot . '/mod/choice/lib.php');
31 /**
32  * Choice module external functions
33  *
34  * @package    mod_choice
35  * @category   external
36  * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
37  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  * @since      Moodle 3.0
39  */
40 class mod_choice_external extends external_api {
42     /**
43      * Describes the parameters for get_choices_by_courses.
44      *
45      * @return external_external_function_parameters
46      * @since Moodle 3.0
47      */
48     public static function get_choice_results_parameters() {
49         return new external_function_parameters (array('choiceid' => new external_value(PARAM_INT, 'choice instance id')));
50     }
51     /**
52      * Returns user's results for a specific choice
53      * and a list of those users that did not answered yet.
54      *
55      * @param int $choiceid the choice instance id
56      * @return array of responses details
57      * @since Moodle 3.0
58      */
59     public static function get_choice_results($choiceid) {
60         global $USER;
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");
66         }
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;
80         }
81         $results = prepare_choice_show_results($choice, $course, $cm, $users);
83         $options = array();
84         $fullnamecap = has_capability('moodle/site:viewfullnames', $context);
85         foreach ($results->options as $optionid => $option) {
87             $userresponses = array();
88             $numberofuser = 0;
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) {
96                         $response = array();
97                         $response['userid'] = $userresponse->id;
98                         $response['fullname'] = fullname($userresponse, $fullnamecap);
99                         $usercontext = context_user::instance($userresponse->id, IGNORE_MISSING);
100                         if ($usercontext) {
101                             $profileimageurl = moodle_url::make_webservice_pluginfile_url($usercontext->id, 'user', 'icon', null,
102                                                                                          '/', 'f1')->out(false);
103                         } else {
104                             $profileimageurl = '';
105                         }
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;
111                             }
112                         }
113                         $userresponses[] = $response;
114                     }
115                 }
116             }
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
124                               );
125         }
127         $warnings = array();
128         return array(
129             'options' => $options,
130             'warnings' => $warnings
131         );
132     }
134     /**
135      * Describes the get_choice_results return value.
136      *
137      * @return external_single_structure
138      * @since Moodle 3.0
139      */
140     public static function get_choice_results_returns() {
141         return new external_single_structure(
142             array(
143                 'options' => new external_multiple_structure(
144                     new external_single_structure(
145                         array(
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(
151                                      array(
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),
157                                      ), 'User responses'
158                                  )
159                             ),
160                             'numberofuser' => new external_value(PARAM_INT, 'number of users answers'),
161                             'percentageamount' => new external_value(PARAM_FLOAT, 'percentage of users answers')
162                         ), 'Options'
163                     )
164                 ),
165                 'warnings' => new external_warnings(),
166             )
167         );
168     }
170     /**
171      * Describes the parameters for mod_choice_get_choice_options.
172      *
173      * @return external_external_function_parameters
174      * @since Moodle 3.0
175      */
176     public static function get_choice_options_parameters() {
177         return new external_function_parameters (array('choiceid' => new external_value(PARAM_INT, 'choice instance id')));
178     }
180     /**
181      * Returns options for a specific choice
182      *
183      * @param int $choiceid the choice instance id
184      * @return array of options details
185      * @since Moodle 3.0
186      */
187     public static function get_choice_options($choiceid) {
188         global $USER;
189         $warnings = array();
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");
194         }
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);
206         $timenow = time();
207         $choiceopen = true;
208         $showpreview = false;
210         if ($choice->timeclose != 0) {
211             if ($choice->timeopen > $timenow) {
212                 $choiceopen = false;
213                 $warnings[1] = get_string("notopenyet", "choice", userdate($choice->timeopen));
214                 if ($choice->showpreview) {
215                     $warnings[2] = get_string('previewonly', 'choice', userdate($choice->timeopen));
216                     $showpreview = true;
217                 }
218             }
219             if ($timenow > $choice->timeclose) {
220                 $choiceopen = false;
221                 $warnings[3] = get_string("expired", "choice", userdate($choice->timeclose));
222             }
223         }
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;
240                     } else {
241                         $optionarr[$field] = 0;
242                     }
243                 }
244                 // When showpreview is active, we show options as disabled.
245                 if ($showpreview or ($optionarr['checked'] == 1 and !$choice->allowupdate)) {
246                     $optionarr['disabled'] = 1;
247                 }
248                 $optionsarray[] = $optionarr;
249             }
250         }
251         foreach ($warnings as $key => $message) {
252             $warnings[$key] = array(
253                 'item' => 'choice',
254                 'itemid' => $cm->id,
255                 'warningcode' => $key,
256                 'message' => $message
257             );
258         }
259         return array(
260             'options' => $optionsarray,
261             'warnings' => $warnings
262         );
263     }
265     /**
266      * Describes the get_choice_results return value.
267      *
268      * @return external_multiple_structure
269      * @since Moodle 3.0
270      */
271     public static function get_choice_options_returns() {
272         return new external_single_structure(
273             array(
274                 'options' => new external_multiple_structure(
275                     new external_single_structure(
276                         array(
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'),
284                             )
285                     ), 'Options'
286                 ),
287                 'warnings' => new external_warnings(),
288             )
289         );
290     }
292     /**
293      * Describes the parameters for submit_choice_response.
294      *
295      * @return external_external_function_parameters
296      * @since Moodle 3.0
297      */
298     public static function submit_choice_response_parameters() {
299         return new external_function_parameters (
300             array(
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'
305                 ),
306             )
307         );
308     }
310     /**
311      * Submit choice responses
312      *
313      * @param int $choiceid the choice instance id
314      * @param array $responses the response ids
315      * @return array ansers informatinon and warnings
316      * @since Moodle 3.0
317      */
318     public static function submit_choice_response($choiceid, $responses) {
319         global $USER;
321         $warnings = array();
322         $params = self::validate_parameters(self::submit_choice_response_parameters(),
323                                             array(
324                                                 'choiceid' => $choiceid,
325                                                 'responses' => $responses
326                                             ));
328         if (!$choice = choice_get_choice($params['choiceid'])) {
329             throw new moodle_exception("invalidcoursemodule", "error");
330         }
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);
338         $timenow = time();
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));
344             }
345         }
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']);
352             }
353             choice_user_submit_response($params['responses'], $choice, $USER->id, $course, $cm);
354         } else {
355             throw new moodle_exception('missingrequiredcapability', 'webservice', '', 'allowupdate');
356         }
357         $answers = choice_get_my_response($choice);
359         return array(
360             'answers' => $answers,
361             'warnings' => $warnings
362         );
363     }
365     /**
366      * Describes the submit_choice_response return value.
367      *
368      * @return external_multiple_structure
369      * @since Moodle 3.0
370      */
371     public static function submit_choice_response_returns() {
372         return new external_single_structure(
373             array(
374                 'answers' => new external_multiple_structure(
375                      new external_single_structure(
376                          array(
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')
382                          ), 'Answers'
383                      )
384                 ),
385                 'warnings' => new external_warnings(),
386             )
387         );
388     }
390     /**
391      * Returns description of method parameters
392      *
393      * @return external_function_parameters
394      * @since Moodle 3.0
395      */
396     public static function view_choice_parameters() {
397         return new external_function_parameters(
398             array(
399                 'choiceid' => new external_value(PARAM_INT, 'choice instance id')
400             )
401         );
402     }
404     /**
405      * Trigger the course module viewed event and update the module completion status.
406      *
407      * @param int $choiceid the choice instance id
408      * @return array of warnings and status result
409      * @since Moodle 3.0
410      * @throws moodle_exception
411      */
412     public static function view_choice($choiceid) {
413         global $CFG;
415         $params = self::validate_parameters(self::view_choice_parameters(),
416                                             array(
417                                                 'choiceid' => $choiceid
418                                             ));
419         $warnings = array();
421         // Request and permission validation.
422         if (!$choice = choice_get_choice($params['choiceid'])) {
423             throw new moodle_exception("invalidcoursemodule", "error");
424         }
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);
433         $result = array();
434         $result['status'] = true;
435         $result['warnings'] = $warnings;
436         return $result;
437     }
439     /**
440      * Returns description of method result value
441      *
442      * @return external_description
443      * @since Moodle 3.0
444      */
445     public static function view_choice_returns() {
446         return new external_single_structure(
447             array(
448                 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
449                 'warnings' => new external_warnings()
450             )
451         );
452     }
454     /**
455      * Describes the parameters for get_choices_by_courses.
456      *
457      * @return external_external_function_parameters
458      * @since Moodle 3.0
459      */
460     public static function get_choices_by_courses_parameters() {
461         return new external_function_parameters (
462             array(
463                 'courseids' => new external_multiple_structure(
464                     new external_value(PARAM_INT, 'course id'), 'Array of course ids', VALUE_DEFAULT, array()
465                 ),
466             )
467         );
468     }
470     /**
471      * Returns a list of choices in a provided list of courses,
472      * if no list is provided all choices that the user can view will be returned.
473      *
474      * @param array $courseids the course ids
475      * @return array of choices details
476      * @since Moodle 3.0
477      */
478     public static function get_choices_by_courses($courseids = array()) {
479         global $CFG;
481         $returnedchoices = array();
482         $warnings = array();
484         $params = self::validate_parameters(self::get_choices_by_courses_parameters(), array('courseids' => $courseids));
486         if (empty($params['courseids'])) {
487             $params['courseids'] = array_keys(enrol_get_my_courses());
488         }
490         // Ensure there are courseids to loop through.
491         if (!empty($params['courseids'])) {
493             list($courses, $warnings) = external_util::validate_courses($params['courseids']);
495             // Get the choices in this course, this function checks users visibility permissions.
496             // We can avoid then additional validate_context calls.
497             $choices = get_all_instances_in_courses("choice", $courses);
498             foreach ($choices as $choice) {
499                 $context = context_module::instance($choice->coursemodule);
500                 // Entry to return.
501                 $choicedetails = array();
502                 // First, we return information that any user can see in the web interface.
503                 $choicedetails['id'] = $choice->id;
504                 $choicedetails['coursemodule'] = $choice->coursemodule;
505                 $choicedetails['course'] = $choice->course;
506                 $choicedetails['name']  = format_string($choice->name, true, array('context' => $context));;
507                 // Format intro.
508                 list($choicedetails['intro'], $choicedetails['introformat']) =
509                     external_format_text($choice->intro, $choice->introformat,
510                                             $context->id, 'mod_choice', 'intro', null);
512                 if (has_capability('mod/choice:choose', $context)) {
513                     $choicedetails['publish']  = $choice->publish;
514                     $choicedetails['showresults']  = $choice->showresults;
515                     $choicedetails['showpreview']  = $choice->showpreview;
516                     $choicedetails['timeopen']  = $choice->timeopen;
517                     $choicedetails['timeclose']  = $choice->timeclose;
518                     $choicedetails['display']  = $choice->display;
519                     $choicedetails['allowupdate']  = $choice->allowupdate;
520                     $choicedetails['allowmultiple']  = $choice->allowmultiple;
521                     $choicedetails['limitanswers']  = $choice->limitanswers;
522                     $choicedetails['showunanswered']  = $choice->showunanswered;
523                     $choicedetails['includeinactive']  = $choice->includeinactive;
524                 }
526                 if (has_capability('moodle/course:manageactivities', $context)) {
527                     $choicedetails['timemodified']  = $choice->timemodified;
528                     $choicedetails['completionsubmit']  = $choice->completionsubmit;
529                     $choicedetails['section']  = $choice->section;
530                     $choicedetails['visible']  = $choice->visible;
531                     $choicedetails['groupmode']  = $choice->groupmode;
532                     $choicedetails['groupingid']  = $choice->groupingid;
533                 }
534                 $returnedchoices[] = $choicedetails;
535             }
536         }
537         $result = array();
538         $result['choices'] = $returnedchoices;
539         $result['warnings'] = $warnings;
540         return $result;
541     }
543     /**
544      * Describes the mod_choice_get_choices_by_courses return value.
545      *
546      * @return external_single_structure
547      * @since Moodle 3.0
548      */
549     public static function get_choices_by_courses_returns() {
550         return new external_single_structure(
551             array(
552                 'choices' => new external_multiple_structure(
553                     new external_single_structure(
554                         array(
555                             'id' => new external_value(PARAM_INT, 'Choice instance id'),
556                             'coursemodule' => new external_value(PARAM_INT, 'Course module id'),
557                             'course' => new external_value(PARAM_INT, 'Course id'),
558                             'name' => new external_value(PARAM_TEXT, 'Choice name'),
559                             'intro' => new external_value(PARAM_RAW, 'The choice intro'),
560                             'introformat' => new external_format_value('intro'),
561                             'publish' => new external_value(PARAM_BOOL, 'If choice is published', VALUE_OPTIONAL),
562                             'showresults' => new external_value(PARAM_INT, '0 never, 1 after answer, 2 after close, 3 always',
563                                                                 VALUE_OPTIONAL),
564                             'display' => new external_value(PARAM_INT, 'Display mode (vertical, horizontal)', VALUE_OPTIONAL),
565                             'allowupdate' => new external_value(PARAM_BOOL, 'Allow update', VALUE_OPTIONAL),
566                             'allowmultiple' => new external_value(PARAM_BOOL, 'Allow multiple choices', VALUE_OPTIONAL),
567                             'showunanswered' => new external_value(PARAM_BOOL, 'Show users who not answered yet', VALUE_OPTIONAL),
568                             'includeinactive' => new external_value(PARAM_BOOL, 'Include inactive users', VALUE_OPTIONAL),
569                             'limitanswers' => new external_value(PARAM_BOOL, 'Limit unswers', VALUE_OPTIONAL),
570                             'timeopen' => new external_value(PARAM_INT, 'Date of opening validity', VALUE_OPTIONAL),
571                             'timeclose' => new external_value(PARAM_INT, 'Date of closing validity', VALUE_OPTIONAL),
572                             'showpreview' => new external_value(PARAM_BOOL, 'Show preview before timeopen', VALUE_OPTIONAL),
573                             'timemodified' => new external_value(PARAM_INT, 'Time of last modification', VALUE_OPTIONAL),
574                             'completionsubmit' => new external_value(PARAM_BOOL, 'Completion on user submission', VALUE_OPTIONAL),
575                             'section' => new external_value(PARAM_INT, 'Course section id', VALUE_OPTIONAL),
576                             'visible' => new external_value(PARAM_BOOL, 'Visible', VALUE_OPTIONAL),
577                             'groupmode' => new external_value(PARAM_INT, 'Group mode', VALUE_OPTIONAL),
578                             'groupingid' => new external_value(PARAM_INT, 'Group id', VALUE_OPTIONAL),
579                         ), 'Choices'
580                     )
581                 ),
582                 'warnings' => new external_warnings(),
583             )
584         );
585     }
587     /**
588      * Describes the parameters for delete_choice_responses.
589      *
590      * @return external_external_function_parameters
591      * @since Moodle 3.0
592      */
593     public static function delete_choice_responses_parameters() {
594         return new external_function_parameters (
595             array(
596                 'choiceid' => new external_value(PARAM_INT, 'choice instance id'),
597                 'responses' => new external_multiple_structure(
598                     new external_value(PARAM_INT, 'response id'),
599                     'Array of response ids, empty for deleting all the user responses',
600                     VALUE_DEFAULT,
601                     array()
602                 ),
603             )
604         );
605     }
607     /**
608      * Delete the given submitted responses in a choice
609      *
610      * @param int $choiceid the choice instance id
611      * @param array $responses the response ids,  empty for deleting all the user responses
612      * @return array status information and warnings
613      * @throws moodle_exception
614      * @since Moodle 3.0
615      */
616     public static function delete_choice_responses($choiceid, $responses = array()) {
618         $status = false;
619         $warnings = array();
620         $params = self::validate_parameters(self::delete_choice_responses_parameters(),
621                                             array(
622                                                 'choiceid' => $choiceid,
623                                                 'responses' => $responses
624                                             ));
626         if (!$choice = choice_get_choice($params['choiceid'])) {
627             throw new moodle_exception("invalidcoursemodule", "error");
628         }
629         list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');
631         $context = context_module::instance($cm->id);
632         self::validate_context($context);
634         require_capability('mod/choice:choose', $context);
636         // If we have the capability, delete all the passed responses.
637         if (has_capability('mod/choice:deleteresponses', $context)) {
638             if (empty($params['responses'])) {
639                 // Get all the responses for the choice.
640                 $params['responses'] = array_keys(choice_get_all_responses($choice));
641             }
642             $status = choice_delete_responses($params['responses'], $choice, $cm, $course);
643         } else if ($choice->allowupdate) {
644             // Check if we can delate our own responses.
645             $timenow = time();
646             if ($choice->timeclose != 0) {
647                 if ($timenow > $choice->timeclose) {
648                     throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose));
649                 }
650             }
651             // Delete only our responses.
652             $myresponses = array_keys(choice_get_my_response($choice));
654             if (empty($params['responses'])) {
655                 $todelete = $myresponses;
656             } else {
657                 $todelete = array();
658                 foreach ($params['responses'] as $response) {
659                     if (!in_array($response, $myresponses)) {
660                         $warnings[] = array(
661                             'item' => 'response',
662                             'itemid' => $response,
663                             'warningcode' => 'nopermissions',
664                             'message' => 'No permission to delete this response'
665                         );
666                     } else {
667                         $todelete[] = $response;
668                     }
669                 }
670             }
672             $status = choice_delete_responses($todelete, $choice, $cm, $course);
673         } else {
674             // The user requires the capability to delete responses.
675             throw new required_capability_exception($context, 'mod/choice:deleteresponses', 'nopermissions', '');
676         }
678         return array(
679             'status' => $status,
680             'warnings' => $warnings
681         );
682     }
684     /**
685      * Describes the delete_choice_responses return value.
686      *
687      * @return external_multiple_structure
688      * @since Moodle 3.0
689      */
690     public static function delete_choice_responses_returns() {
691         return new external_single_structure(
692             array(
693                 'status' => new external_value(PARAM_BOOL, 'status, true if everything went right'),
694                 'warnings' => new external_warnings(),
695             )
696         );
697     }