See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
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/>. 16 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 */ 26 27 use core_course\external\helper_for_get_mods_by_courses; 28 29 defined('MOODLE_INTERNAL') || die; 30 require_once($CFG->libdir . '/externallib.php'); 31 require_once($CFG->dirroot . '/mod/choice/lib.php'); 32 33 /** 34 * Choice module external functions 35 * 36 * @package mod_choice 37 * @category external 38 * @copyright 2015 Costantino Cito <ccito@cvaconsulting.com> 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 * @since Moodle 3.0 41 */ 42 class mod_choice_external extends external_api { 43 44 /** 45 * Describes the parameters for get_choices_by_courses. 46 * 47 * @return external_function_parameters 48 * @since Moodle 3.0 49 */ 50 public static function get_choice_results_parameters() { 51 return new external_function_parameters (array('choiceid' => new external_value(PARAM_INT, 'choice instance id'))); 52 } 53 /** 54 * Returns user's results for a specific choice 55 * and a list of those users that did not answered yet. 56 * 57 * @param int $choiceid the choice instance id 58 * @return array of responses details 59 * @since Moodle 3.0 60 */ 61 public static function get_choice_results($choiceid) { 62 global $USER, $PAGE; 63 64 $params = self::validate_parameters(self::get_choice_results_parameters(), array('choiceid' => $choiceid)); 65 66 if (!$choice = choice_get_choice($params['choiceid'])) { 67 throw new moodle_exception("invalidcoursemodule", "error"); 68 } 69 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice'); 70 71 $context = context_module::instance($cm->id); 72 self::validate_context($context); 73 74 $groupmode = groups_get_activity_groupmode($cm); 75 // Check if we have to include responses from inactive users. 76 $onlyactive = $choice->includeinactive ? false : true; 77 $users = choice_get_response_data($choice, $cm, $groupmode, $onlyactive); 78 // Show those who haven't answered the question. 79 if (!empty($choice->showunanswered)) { 80 $choice->option[0] = get_string('notanswered', 'choice'); 81 $choice->maxanswers[0] = 0; 82 } 83 $results = prepare_choice_show_results($choice, $course, $cm, $users); 84 85 $options = array(); 86 $fullnamecap = has_capability('moodle/site:viewfullnames', $context); 87 foreach ($results->options as $optionid => $option) { 88 89 $userresponses = array(); 90 $numberofuser = 0; 91 $percentageamount = 0; 92 if (property_exists($option, 'user') and 93 (has_capability('mod/choice:readresponses', $context) or choice_can_view_results($choice))) { 94 $numberofuser = count($option->user); 95 $percentageamount = ((float)$numberofuser / (float)$results->numberofuser) * 100.0; 96 if ($choice->publish) { 97 foreach ($option->user as $userresponse) { 98 $response = array(); 99 $response['userid'] = $userresponse->id; 100 $response['fullname'] = fullname($userresponse, $fullnamecap); 101 102 $userpicture = new user_picture($userresponse); 103 $userpicture->size = 1; // Size f1. 104 $response['profileimageurl'] = $userpicture->get_url($PAGE)->out(false); 105 106 // Add optional properties. 107 foreach (array('answerid', 'timemodified') as $field) { 108 if (property_exists($userresponse, 'answerid')) { 109 $response[$field] = $userresponse->$field; 110 } 111 } 112 $userresponses[] = $response; 113 } 114 } 115 } 116 117 $options[] = array('id' => $optionid, 118 'text' => external_format_string($option->text, $context->id), 119 'maxanswer' => $option->maxanswer, 120 'userresponses' => $userresponses, 121 'numberofuser' => $numberofuser, 122 'percentageamount' => $percentageamount 123 ); 124 } 125 126 $warnings = array(); 127 return array( 128 'options' => $options, 129 'warnings' => $warnings 130 ); 131 } 132 133 /** 134 * Describes the get_choice_results return value. 135 * 136 * @return external_single_structure 137 * @since Moodle 3.0 138 */ 139 public static function get_choice_results_returns() { 140 return new external_single_structure( 141 array( 142 'options' => new external_multiple_structure( 143 new external_single_structure( 144 array( 145 'id' => new external_value(PARAM_INT, 'choice instance id'), 146 'text' => new external_value(PARAM_RAW, 'text of the choice'), 147 'maxanswer' => new external_value(PARAM_INT, 'maximum number of answers'), 148 'userresponses' => new external_multiple_structure( 149 new external_single_structure( 150 array( 151 'userid' => new external_value(PARAM_INT, 'user id'), 152 'fullname' => new external_value(PARAM_NOTAGS, 'user full name'), 153 'profileimageurl' => new external_value(PARAM_URL, 'profile user image url'), 154 'answerid' => new external_value(PARAM_INT, 'answer id', VALUE_OPTIONAL), 155 'timemodified' => new external_value(PARAM_INT, 'time of modification', VALUE_OPTIONAL), 156 ), 'User responses' 157 ) 158 ), 159 'numberofuser' => new external_value(PARAM_INT, 'number of users answers'), 160 'percentageamount' => new external_value(PARAM_FLOAT, 'percentage of users answers') 161 ), 'Options' 162 ) 163 ), 164 'warnings' => new external_warnings(), 165 ) 166 ); 167 } 168 169 /** 170 * Describes the parameters for mod_choice_get_choice_options. 171 * 172 * @return external_function_parameters 173 * @since Moodle 3.0 174 */ 175 public static function get_choice_options_parameters() { 176 return new external_function_parameters (array('choiceid' => new external_value(PARAM_INT, 'choice instance id'))); 177 } 178 179 /** 180 * Returns options for a specific choice 181 * 182 * @param int $choiceid the choice instance id 183 * @return array of options details 184 * @since Moodle 3.0 185 */ 186 public static function get_choice_options($choiceid) { 187 global $USER; 188 $warnings = array(); 189 $params = self::validate_parameters(self::get_choice_options_parameters(), array('choiceid' => $choiceid)); 190 191 if (!$choice = choice_get_choice($params['choiceid'])) { 192 throw new moodle_exception("invalidcoursemodule", "error"); 193 } 194 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice'); 195 196 $context = context_module::instance($cm->id); 197 self::validate_context($context); 198 199 require_capability('mod/choice:choose', $context); 200 201 $groupmode = groups_get_activity_groupmode($cm); 202 $onlyactive = $choice->includeinactive ? false : true; 203 $allresponses = choice_get_response_data($choice, $cm, $groupmode, $onlyactive); 204 205 $timenow = time(); 206 $choiceopen = true; 207 $showpreview = false; 208 209 if (!empty($choice->timeopen) && ($choice->timeopen > $timenow)) { 210 $choiceopen = false; 211 $warnings[1] = get_string("notopenyet", "choice", userdate($choice->timeopen)); 212 if ($choice->showpreview) { 213 $warnings[2] = get_string('previewonly', 'choice', userdate($choice->timeopen)); 214 $showpreview = true; 215 } 216 } 217 if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) { 218 $choiceopen = false; 219 $warnings[3] = get_string("expired", "choice", userdate($choice->timeclose)); 220 } 221 222 $optionsarray = array(); 223 224 if ($choiceopen or $showpreview) { 225 226 $options = choice_prepare_options($choice, $USER, $cm, $allresponses); 227 228 foreach ($options['options'] as $option) { 229 $optionarr = array(); 230 $optionarr['id'] = $option->attributes->value; 231 $optionarr['text'] = external_format_string($option->text, $context->id); 232 $optionarr['maxanswers'] = $option->maxanswers; 233 $optionarr['displaylayout'] = $option->displaylayout; 234 $optionarr['countanswers'] = $option->countanswers; 235 foreach (array('checked', 'disabled') as $field) { 236 if (property_exists($option->attributes, $field) and $option->attributes->$field == 1) { 237 $optionarr[$field] = 1; 238 } else { 239 $optionarr[$field] = 0; 240 } 241 } 242 // When showpreview is active, we show options as disabled. 243 if ($showpreview or ($optionarr['checked'] == 1 and !$choice->allowupdate)) { 244 $optionarr['disabled'] = 1; 245 } 246 $optionsarray[] = $optionarr; 247 } 248 } 249 foreach ($warnings as $key => $message) { 250 $warnings[$key] = array( 251 'item' => 'choice', 252 'itemid' => $cm->id, 253 'warningcode' => $key, 254 'message' => $message 255 ); 256 } 257 return array( 258 'options' => $optionsarray, 259 'warnings' => $warnings 260 ); 261 } 262 263 /** 264 * Describes the get_choice_results return value. 265 * 266 * @return external_multiple_structure 267 * @since Moodle 3.0 268 */ 269 public static function get_choice_options_returns() { 270 return new external_single_structure( 271 array( 272 'options' => new external_multiple_structure( 273 new external_single_structure( 274 array( 275 'id' => new external_value(PARAM_INT, 'option id'), 276 'text' => new external_value(PARAM_RAW, 'text of the choice'), 277 'maxanswers' => new external_value(PARAM_INT, 'maximum number of answers'), 278 'displaylayout' => new external_value(PARAM_BOOL, 'true for orizontal, otherwise vertical'), 279 'countanswers' => new external_value(PARAM_INT, 'number of answers'), 280 'checked' => new external_value(PARAM_BOOL, 'we already answered'), 281 'disabled' => new external_value(PARAM_BOOL, 'option disabled'), 282 ) 283 ), 'Options' 284 ), 285 'warnings' => new external_warnings(), 286 ) 287 ); 288 } 289 290 /** 291 * Describes the parameters for submit_choice_response. 292 * 293 * @return external_function_parameters 294 * @since Moodle 3.0 295 */ 296 public static function submit_choice_response_parameters() { 297 return new external_function_parameters ( 298 array( 299 'choiceid' => new external_value(PARAM_INT, 'choice instance id'), 300 'responses' => new external_multiple_structure( 301 new external_value(PARAM_INT, 'answer id'), 302 'Array of response ids' 303 ), 304 ) 305 ); 306 } 307 308 /** 309 * Submit choice responses 310 * 311 * @param int $choiceid the choice instance id 312 * @param array $responses the response ids 313 * @return array answers information and warnings 314 * @since Moodle 3.0 315 */ 316 public static function submit_choice_response($choiceid, $responses) { 317 global $USER; 318 319 $warnings = array(); 320 $params = self::validate_parameters(self::submit_choice_response_parameters(), 321 array( 322 'choiceid' => $choiceid, 323 'responses' => $responses 324 )); 325 326 if (!$choice = choice_get_choice($params['choiceid'])) { 327 throw new moodle_exception("invalidcoursemodule", "error"); 328 } 329 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice'); 330 331 $context = context_module::instance($cm->id); 332 self::validate_context($context); 333 334 require_capability('mod/choice:choose', $context); 335 336 $timenow = time(); 337 if (!empty($choice->timeopen) && ($choice->timeopen > $timenow)) { 338 throw new moodle_exception("notopenyet", "choice", '', userdate($choice->timeopen)); 339 } else if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) { 340 throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose)); 341 } 342 343 if (!choice_get_my_response($choice) or $choice->allowupdate) { 344 // When a single response is given, we convert the array to a simple variable 345 // in order to avoid choice_user_submit_response to check with allowmultiple even 346 // for a single response. 347 if (count($params['responses']) == 1) { 348 $params['responses'] = reset($params['responses']); 349 } 350 choice_user_submit_response($params['responses'], $choice, $USER->id, $course, $cm); 351 } else { 352 throw new moodle_exception('missingrequiredcapability', 'webservice', '', 'allowupdate'); 353 } 354 $answers = choice_get_my_response($choice); 355 356 return array( 357 'answers' => $answers, 358 'warnings' => $warnings 359 ); 360 } 361 362 /** 363 * Describes the submit_choice_response return value. 364 * 365 * @return external_multiple_structure 366 * @since Moodle 3.0 367 */ 368 public static function submit_choice_response_returns() { 369 return new external_single_structure( 370 array( 371 'answers' => new external_multiple_structure( 372 new external_single_structure( 373 array( 374 'id' => new external_value(PARAM_INT, 'answer id'), 375 'choiceid' => new external_value(PARAM_INT, 'choiceid'), 376 'userid' => new external_value(PARAM_INT, 'user id'), 377 'optionid' => new external_value(PARAM_INT, 'optionid'), 378 'timemodified' => new external_value(PARAM_INT, 'time of last modification') 379 ), 'Answers' 380 ) 381 ), 382 'warnings' => new external_warnings(), 383 ) 384 ); 385 } 386 387 /** 388 * Returns description of method parameters 389 * 390 * @return external_function_parameters 391 * @since Moodle 3.0 392 */ 393 public static function view_choice_parameters() { 394 return new external_function_parameters( 395 array( 396 'choiceid' => new external_value(PARAM_INT, 'choice instance id') 397 ) 398 ); 399 } 400 401 /** 402 * Trigger the course module viewed event and update the module completion status. 403 * 404 * @param int $choiceid the choice instance id 405 * @return array of warnings and status result 406 * @since Moodle 3.0 407 * @throws moodle_exception 408 */ 409 public static function view_choice($choiceid) { 410 global $CFG; 411 412 $params = self::validate_parameters(self::view_choice_parameters(), 413 array( 414 'choiceid' => $choiceid 415 )); 416 $warnings = array(); 417 418 // Request and permission validation. 419 if (!$choice = choice_get_choice($params['choiceid'])) { 420 throw new moodle_exception("invalidcoursemodule", "error"); 421 } 422 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice'); 423 424 $context = context_module::instance($cm->id); 425 self::validate_context($context); 426 427 // Trigger course_module_viewed event and completion. 428 choice_view($choice, $course, $cm, $context); 429 430 $result = array(); 431 $result['status'] = true; 432 $result['warnings'] = $warnings; 433 return $result; 434 } 435 436 /** 437 * Returns description of method result value 438 * 439 * @return external_description 440 * @since Moodle 3.0 441 */ 442 public static function view_choice_returns() { 443 return new external_single_structure( 444 array( 445 'status' => new external_value(PARAM_BOOL, 'status: true if success'), 446 'warnings' => new external_warnings() 447 ) 448 ); 449 } 450 451 /** 452 * Describes the parameters for get_choices_by_courses. 453 * 454 * @return external_function_parameters 455 * @since Moodle 3.0 456 */ 457 public static function get_choices_by_courses_parameters() { 458 return new external_function_parameters ( 459 array( 460 'courseids' => new external_multiple_structure( 461 new external_value(PARAM_INT, 'course id'), 'Array of course ids', VALUE_DEFAULT, array() 462 ), 463 ) 464 ); 465 } 466 467 /** 468 * Returns a list of choices in a provided list of courses, 469 * if no list is provided all choices that the user can view will be returned. 470 * 471 * @param array $courseids the course ids 472 * @return array of choices details 473 * @since Moodle 3.0 474 */ 475 public static function get_choices_by_courses($courseids = array()) { 476 $returnedchoices = array(); 477 $warnings = array(); 478 479 $params = self::validate_parameters(self::get_choices_by_courses_parameters(), array('courseids' => $courseids)); 480 481 $courses = array(); 482 if (empty($params['courseids'])) { 483 $courses = enrol_get_my_courses(); 484 $params['courseids'] = array_keys($courses); 485 } 486 487 // Ensure there are courseids to loop through. 488 if (!empty($params['courseids'])) { 489 490 list($courses, $warnings) = external_util::validate_courses($params['courseids'], $courses); 491 492 // Get the choices in this course, this function checks users visibility permissions. 493 // We can avoid then additional validate_context calls. 494 $choices = get_all_instances_in_courses("choice", $courses); 495 foreach ($choices as $choice) { 496 $context = context_module::instance($choice->coursemodule); 497 498 $choicedetails = helper_for_get_mods_by_courses::standard_coursemodule_element_values($choice, 'mod_choice'); 499 500 if (has_capability('mod/choice:choose', $context)) { 501 $choicedetails['publish'] = $choice->publish; 502 $choicedetails['showresults'] = $choice->showresults; 503 $choicedetails['showpreview'] = $choice->showpreview; 504 $choicedetails['timeopen'] = $choice->timeopen; 505 $choicedetails['timeclose'] = $choice->timeclose; 506 $choicedetails['display'] = $choice->display; 507 $choicedetails['allowupdate'] = $choice->allowupdate; 508 $choicedetails['allowmultiple'] = $choice->allowmultiple; 509 $choicedetails['limitanswers'] = $choice->limitanswers; 510 $choicedetails['showunanswered'] = $choice->showunanswered; 511 $choicedetails['includeinactive'] = $choice->includeinactive; 512 $choicedetails['showavailable'] = $choice->showavailable; 513 } 514 515 if (has_capability('moodle/course:manageactivities', $context)) { 516 $choicedetails['timemodified'] = $choice->timemodified; 517 $choicedetails['completionsubmit'] = $choice->completionsubmit; 518 } 519 $returnedchoices[] = $choicedetails; 520 } 521 } 522 $result = array(); 523 $result['choices'] = $returnedchoices; 524 $result['warnings'] = $warnings; 525 return $result; 526 } 527 528 /** 529 * Describes the mod_choice_get_choices_by_courses return value. 530 * 531 * @return external_single_structure 532 * @since Moodle 3.0 533 */ 534 public static function get_choices_by_courses_returns() { 535 return new external_single_structure( 536 array( 537 'choices' => new external_multiple_structure( 538 new external_single_structure(array_merge( 539 helper_for_get_mods_by_courses::standard_coursemodule_elements_returns(), 540 [ 541 'publish' => new external_value(PARAM_BOOL, 'If choice is published', VALUE_OPTIONAL), 542 'showresults' => new external_value(PARAM_INT, '0 never, 1 after answer, 2 after close, 3 always', 543 VALUE_OPTIONAL), 544 'display' => new external_value(PARAM_INT, 'Display mode (vertical, horizontal)', VALUE_OPTIONAL), 545 'allowupdate' => new external_value(PARAM_BOOL, 'Allow update', VALUE_OPTIONAL), 546 'allowmultiple' => new external_value(PARAM_BOOL, 'Allow multiple choices', VALUE_OPTIONAL), 547 'showunanswered' => new external_value(PARAM_BOOL, 'Show users who not answered yet', VALUE_OPTIONAL), 548 'includeinactive' => new external_value(PARAM_BOOL, 'Include inactive users', VALUE_OPTIONAL), 549 'limitanswers' => new external_value(PARAM_BOOL, 'Limit unswers', VALUE_OPTIONAL), 550 'timeopen' => new external_value(PARAM_INT, 'Date of opening validity', VALUE_OPTIONAL), 551 'timeclose' => new external_value(PARAM_INT, 'Date of closing validity', VALUE_OPTIONAL), 552 'showpreview' => new external_value(PARAM_BOOL, 'Show preview before timeopen', VALUE_OPTIONAL), 553 'timemodified' => new external_value(PARAM_INT, 'Time of last modification', VALUE_OPTIONAL), 554 'completionsubmit' => new external_value(PARAM_BOOL, 'Completion on user submission', VALUE_OPTIONAL), 555 'showavailable' => new external_value(PARAM_BOOL, 'Show available spaces', VALUE_OPTIONAL), 556 ] 557 ), 'Choices') 558 ), 559 'warnings' => new external_warnings(), 560 ) 561 ); 562 } 563 564 /** 565 * Describes the parameters for delete_choice_responses. 566 * 567 * @return external_function_parameters 568 * @since Moodle 3.0 569 */ 570 public static function delete_choice_responses_parameters() { 571 return new external_function_parameters ( 572 array( 573 'choiceid' => new external_value(PARAM_INT, 'choice instance id'), 574 'responses' => new external_multiple_structure( 575 new external_value(PARAM_INT, 'response id'), 576 'Array of response ids, empty for deleting all the current user responses.', 577 VALUE_DEFAULT, 578 array() 579 ), 580 ) 581 ); 582 } 583 584 /** 585 * Delete the given submitted responses in a choice 586 * 587 * @param int $choiceid the choice instance id 588 * @param array $responses the response ids, empty for deleting all the current user responses 589 * @return array status information and warnings 590 * @throws moodle_exception 591 * @since Moodle 3.0 592 */ 593 public static function delete_choice_responses($choiceid, $responses = array()) { 594 595 $status = false; 596 $warnings = array(); 597 $params = self::validate_parameters(self::delete_choice_responses_parameters(), 598 array( 599 'choiceid' => $choiceid, 600 'responses' => $responses 601 )); 602 603 if (!$choice = choice_get_choice($params['choiceid'])) { 604 throw new moodle_exception("invalidcoursemodule", "error"); 605 } 606 list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice'); 607 608 $context = context_module::instance($cm->id); 609 self::validate_context($context); 610 611 require_capability('mod/choice:choose', $context); 612 613 $candeleteall = has_capability('mod/choice:deleteresponses', $context); 614 if ($candeleteall || $choice->allowupdate) { 615 616 // Check if we can delete our own responses. 617 if (!$candeleteall) { 618 $timenow = time(); 619 if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) { 620 throw new moodle_exception("expired", "choice", '', userdate($choice->timeclose)); 621 } 622 } 623 624 if (empty($params['responses'])) { 625 // No responses indicated so delete only my responses. 626 $todelete = array_keys(choice_get_my_response($choice)); 627 } else { 628 // Fill an array with the responses that can be deleted for this choice. 629 if ($candeleteall) { 630 // Teacher/managers can delete any. 631 $allowedresponses = array_keys(choice_get_all_responses($choice)); 632 } else { 633 // Students can delete only their own responses. 634 $allowedresponses = array_keys(choice_get_my_response($choice)); 635 } 636 637 $todelete = array(); 638 foreach ($params['responses'] as $response) { 639 if (!in_array($response, $allowedresponses)) { 640 $warnings[] = array( 641 'item' => 'response', 642 'itemid' => $response, 643 'warningcode' => 'nopermissions', 644 'message' => 'Invalid response id, the response does not exist or you are not allowed to delete it.' 645 ); 646 } else { 647 $todelete[] = $response; 648 } 649 } 650 } 651 652 $status = choice_delete_responses($todelete, $choice, $cm, $course); 653 } else { 654 // The user requires the capability to delete responses. 655 throw new required_capability_exception($context, 'mod/choice:deleteresponses', 'nopermissions', ''); 656 } 657 658 return array( 659 'status' => $status, 660 'warnings' => $warnings 661 ); 662 } 663 664 /** 665 * Describes the delete_choice_responses return value. 666 * 667 * @return external_multiple_structure 668 * @since Moodle 3.0 669 */ 670 public static function delete_choice_responses_returns() { 671 return new external_single_structure( 672 array( 673 'status' => new external_value(PARAM_BOOL, 'status, true if everything went right'), 674 'warnings' => new external_warnings(), 675 ) 676 ); 677 } 678 679 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body