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 /** 19 * External calendar API 20 * 21 * @package core_calendar 22 * @category external 23 * @copyright 2012 Ankit Agarwal 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 * @since Moodle 2.5 26 */ 27 28 defined('MOODLE_INTERNAL') || die; 29 30 require_once("$CFG->libdir/externallib.php"); 31 require_once($CFG->dirroot . '/calendar/lib.php'); 32 33 use \core_calendar\local\api as local_api; 34 use \core_calendar\local\event\container as event_container; 35 use \core_calendar\local\event\forms\create as create_event_form; 36 use \core_calendar\local\event\forms\update as update_event_form; 37 use \core_calendar\local\event\mappers\create_update_form_mapper; 38 use \core_calendar\external\event_exporter; 39 use \core_calendar\external\events_exporter; 40 use \core_calendar\external\events_grouped_by_course_exporter; 41 use \core_calendar\external\events_related_objects_cache; 42 43 /** 44 * Calendar external functions 45 * 46 * @package core_calendar 47 * @category external 48 * @copyright 2012 Ankit Agarwal 49 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 50 * @since Moodle 2.5 51 */ 52 class core_calendar_external extends external_api { 53 54 55 /** 56 * Returns description of method parameters 57 * 58 * @return external_function_parameters 59 * @since Moodle 2.5 60 */ 61 public static function delete_calendar_events_parameters() { 62 return new external_function_parameters( 63 array('events' => new external_multiple_structure( 64 new external_single_structure( 65 array( 66 'eventid' => new external_value(PARAM_INT, 'Event ID', VALUE_REQUIRED, '', NULL_NOT_ALLOWED), 67 'repeat' => new external_value(PARAM_BOOL, 'Delete comeplete series if repeated event') 68 ), 'List of events to delete' 69 ) 70 ) 71 ) 72 ); 73 } 74 75 /** 76 * Delete Calendar events 77 * 78 * @param array $eventids A list of event ids with repeat flag to delete 79 * @return null 80 * @since Moodle 2.5 81 */ 82 public static function delete_calendar_events($events) { 83 global $DB; 84 85 // Parameter validation. 86 $params = self::validate_parameters(self:: delete_calendar_events_parameters(), array('events' => $events)); 87 88 $transaction = $DB->start_delegated_transaction(); 89 90 foreach ($params['events'] as $event) { 91 $eventobj = calendar_event::load($event['eventid']); 92 93 // Let's check if the user is allowed to delete an event. 94 if (!calendar_delete_event_allowed($eventobj)) { 95 throw new moodle_exception('nopermissions', 'error', '', get_string('deleteevent', 'calendar')); 96 } 97 // Time to do the magic. 98 $eventobj->delete($event['repeat']); 99 } 100 101 // Everything done smoothly, let's commit. 102 $transaction->allow_commit(); 103 104 return null; 105 } 106 107 /** 108 * Returns description of method result value 109 * 110 * @return external_description 111 * @since Moodle 2.5 112 */ 113 public static function delete_calendar_events_returns() { 114 return null; 115 } 116 117 /** 118 * Returns description of method parameters 119 * 120 * @return external_function_parameters 121 * @since Moodle 2.5 122 */ 123 public static function get_calendar_events_parameters() { 124 return new external_function_parameters( 125 array('events' => new external_single_structure( 126 array( 127 'eventids' => new external_multiple_structure( 128 new external_value(PARAM_INT, 'event ids') 129 , 'List of event ids', 130 VALUE_DEFAULT, array()), 131 'courseids' => new external_multiple_structure( 132 new external_value(PARAM_INT, 'course ids') 133 , 'List of course ids for which events will be returned', 134 VALUE_DEFAULT, array()), 135 'groupids' => new external_multiple_structure( 136 new external_value(PARAM_INT, 'group ids') 137 , 'List of group ids for which events should be returned', 138 VALUE_DEFAULT, array()), 139 'categoryids' => new external_multiple_structure( 140 new external_value(PARAM_INT, 'Category ids'), 141 'List of category ids for which events will be returned', 142 VALUE_DEFAULT, array()), 143 ), 'Event details', VALUE_DEFAULT, array()), 144 'options' => new external_single_structure( 145 array( 146 'userevents' => new external_value(PARAM_BOOL, 147 "Set to true to return current user's user events", 148 VALUE_DEFAULT, true, NULL_ALLOWED), 149 'siteevents' => new external_value(PARAM_BOOL, 150 "Set to true to return site events", 151 VALUE_DEFAULT, true, NULL_ALLOWED), 152 'timestart' => new external_value(PARAM_INT, 153 "Time from which events should be returned", 154 VALUE_DEFAULT, 0, NULL_ALLOWED), 155 'timeend' => new external_value(PARAM_INT, 156 "Time to which the events should be returned. We treat 0 and null as no end", 157 VALUE_DEFAULT, 0, NULL_ALLOWED), 158 'ignorehidden' => new external_value(PARAM_BOOL, 159 "Ignore hidden events or not", 160 VALUE_DEFAULT, true, NULL_ALLOWED), 161 162 ), 'Options', VALUE_DEFAULT, array()) 163 ) 164 ); 165 } 166 167 /** 168 * Get Calendar events 169 * 170 * @param array $events A list of events 171 * @param array $options various options 172 * @return array Array of event details 173 * @since Moodle 2.5 174 */ 175 public static function get_calendar_events($events = array(), $options = array()) { 176 global $SITE, $DB, $USER; 177 178 // Parameter validation. 179 $params = self::validate_parameters(self::get_calendar_events_parameters(), array('events' => $events, 'options' => $options)); 180 $funcparam = array('courses' => array(), 'groups' => array(), 'categories' => array()); 181 $hassystemcap = has_capability('moodle/calendar:manageentries', context_system::instance()); 182 $warnings = array(); 183 $coursecategories = array(); 184 185 // Let us find out courses and their categories that we can return events from. 186 if (!$hassystemcap) { 187 $courseobjs = enrol_get_my_courses(); 188 $courses = array_keys($courseobjs); 189 190 $coursecategories = array_flip(array_map(function($course) { 191 return $course->category; 192 }, $courseobjs)); 193 194 foreach ($params['events']['courseids'] as $id) { 195 try { 196 $context = context_course::instance($id); 197 self::validate_context($context); 198 $funcparam['courses'][] = $id; 199 } catch (Exception $e) { 200 $warnings[] = array( 201 'item' => 'course', 202 'itemid' => $id, 203 'warningcode' => 'nopermissions', 204 'message' => 'No access rights in course context '.$e->getMessage().$e->getTraceAsString() 205 ); 206 } 207 } 208 } else { 209 $courses = $params['events']['courseids']; 210 $funcparam['courses'] = $courses; 211 212 if (!empty($courses)) { 213 list($wheresql, $sqlparams) = $DB->get_in_or_equal($courses); 214 $wheresql = "id $wheresql"; 215 $coursecategories = array_flip(array_map(function($course) { 216 return $course->category; 217 }, $DB->get_records_select('course', $wheresql, $sqlparams, '', 'category'))); 218 } 219 } 220 221 // Let us findout groups that we can return events from. 222 if (!$hassystemcap) { 223 $groups = groups_get_my_groups(); 224 $groups = array_keys($groups); 225 foreach ($params['events']['groupids'] as $id) { 226 if (in_array($id, $groups)) { 227 $funcparam['groups'][] = $id; 228 } else { 229 $warnings[] = array('item' => $id, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to access this group'); 230 } 231 } 232 } else { 233 $groups = $params['events']['groupids']; 234 $funcparam['groups'] = $groups; 235 } 236 237 $categories = array(); 238 if ($hassystemcap || !empty($courses)) { 239 // Use the category id as the key in the following array. That way we do not have to remove duplicates and 240 // have a faster lookup later. 241 $categories = []; 242 243 if (!empty($params['events']['categoryids'])) { 244 $catobjs = \core_course_category::get_many( 245 array_merge($params['events']['categoryids'], array_keys($coursecategories))); 246 foreach ($catobjs as $catobj) { 247 if (isset($coursecategories[$catobj->id]) || 248 has_capability('moodle/category:manage', $catobj->get_context())) { 249 // If the user has access to a course in this category or can manage the category, 250 // then they can see all parent categories too. 251 $categories[$catobj->id] = true; 252 foreach ($catobj->get_parents() as $catid) { 253 $categories[$catid] = true; 254 } 255 } 256 } 257 $funcparam['categories'] = array_keys($categories); 258 } else { 259 // Fetch all categories where this user has any enrolment, and all categories that this user can manage. 260 $calcatcache = cache::make('core', 'calendar_categories'); 261 // Do not use cache if the user has the system capability as $coursecategories might not represent the 262 // courses the user is enrolled in. 263 $categories = (!$hassystemcap) ? $calcatcache->get('site') : false; 264 if ($categories !== false) { 265 // The ids are stored in a list in the cache. 266 $funcparam['categories'] = $categories; 267 $categories = array_flip($categories); 268 } else { 269 $categories = []; 270 foreach (\core_course_category::get_all() as $category) { 271 if (isset($coursecategories[$category->id]) || 272 has_capability('moodle/category:manage', $category->get_context(), $USER, false)) { 273 // If the user has access to a course in this category or can manage the category, 274 // then they can see all parent categories too. 275 $categories[$category->id] = true; 276 foreach ($category->get_parents() as $catid) { 277 $categories[$catid] = true; 278 } 279 } 280 } 281 $funcparam['categories'] = array_keys($categories); 282 if (!$hassystemcap) { 283 $calcatcache->set('site', $funcparam['categories']); 284 } 285 } 286 } 287 } 288 289 // Do we need user events? 290 if (!empty($params['options']['userevents'])) { 291 $funcparam['users'] = array($USER->id); 292 } else { 293 $funcparam['users'] = false; 294 } 295 296 // Do we need site events? 297 if (!empty($params['options']['siteevents'])) { 298 $funcparam['courses'][] = $SITE->id; 299 } 300 301 // We treat 0 and null as no end. 302 if (empty($params['options']['timeend'])) { 303 $params['options']['timeend'] = PHP_INT_MAX; 304 } 305 306 // Event list does not check visibility and permissions, we'll check that later. 307 $eventlist = calendar_get_legacy_events($params['options']['timestart'], $params['options']['timeend'], 308 $funcparam['users'], $funcparam['groups'], $funcparam['courses'], true, 309 $params['options']['ignorehidden'], $funcparam['categories']); 310 311 // WS expects arrays. 312 $events = array(); 313 314 // We need to get events asked for eventids. 315 if ($eventsbyid = calendar_get_events_by_id($params['events']['eventids'])) { 316 $eventlist += $eventsbyid; 317 } 318 foreach ($eventlist as $eventid => $eventobj) { 319 $event = (array) $eventobj; 320 // Description formatting. 321 $calendareventobj = new calendar_event($event); 322 $event['name'] = $calendareventobj->format_external_name(); 323 list($event['description'], $event['format']) = $calendareventobj->format_external_text(); 324 325 if ($hassystemcap) { 326 // User can see everything, no further check is needed. 327 $events[$eventid] = $event; 328 } else if (!empty($eventobj->modulename)) { 329 $courseid = $eventobj->courseid; 330 if (!$courseid) { 331 if (!$calendareventobj->context || !($context = $calendareventobj->context->get_course_context(false))) { 332 continue; 333 } 334 $courseid = $context->instanceid; 335 } 336 $instances = get_fast_modinfo($courseid)->get_instances_of($eventobj->modulename); 337 if (!empty($instances[$eventobj->instance]->uservisible)) { 338 $events[$eventid] = $event; 339 } 340 } else { 341 // Can the user actually see this event? 342 $eventobj = calendar_event::load($eventobj); 343 if ((($eventobj->courseid == $SITE->id) && (empty($eventobj->categoryid))) || 344 (!empty($eventobj->categoryid) && isset($categories[$eventobj->categoryid])) || 345 (!empty($eventobj->groupid) && in_array($eventobj->groupid, $groups)) || 346 (!empty($eventobj->courseid) && in_array($eventobj->courseid, $courses)) || 347 ($USER->id == $eventobj->userid) || 348 (calendar_edit_event_allowed($eventobj))) { 349 $events[$eventid] = $event; 350 } else { 351 $warnings[] = array('item' => $eventid, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to view this event'); 352 } 353 } 354 } 355 return array('events' => $events, 'warnings' => $warnings); 356 } 357 358 /** 359 * Returns description of method result value 360 * 361 * @return external_description 362 * @since Moodle 2.5 363 */ 364 public static function get_calendar_events_returns() { 365 return new external_single_structure(array( 366 'events' => new external_multiple_structure( new external_single_structure( 367 array( 368 'id' => new external_value(PARAM_INT, 'event id'), 369 'name' => new external_value(PARAM_RAW, 'event name'), 370 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL, null, NULL_ALLOWED), 371 'format' => new external_format_value('description'), 372 'courseid' => new external_value(PARAM_INT, 'course id'), 373 'categoryid' => new external_value(PARAM_INT, 'Category id (only for category events).', 374 VALUE_OPTIONAL), 375 'groupid' => new external_value(PARAM_INT, 'group id'), 376 'userid' => new external_value(PARAM_INT, 'user id'), 377 'repeatid' => new external_value(PARAM_INT, 'repeat id'), 378 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL, null, NULL_ALLOWED), 379 'instance' => new external_value(PARAM_INT, 'instance id'), 380 'eventtype' => new external_value(PARAM_TEXT, 'Event type'), 381 'timestart' => new external_value(PARAM_INT, 'timestart'), 382 'timeduration' => new external_value(PARAM_INT, 'time duration'), 383 'visible' => new external_value(PARAM_INT, 'visible'), 384 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, null, NULL_NOT_ALLOWED), 385 'sequence' => new external_value(PARAM_INT, 'sequence'), 386 'timemodified' => new external_value(PARAM_INT, 'time modified'), 387 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL, null, NULL_ALLOWED), 388 ), 'event') 389 ), 390 'warnings' => new external_warnings() 391 ) 392 ); 393 } 394 395 /** 396 * Returns description of method parameters. 397 * 398 * @since Moodle 3.3 399 * @return external_function_parameters 400 */ 401 public static function get_calendar_action_events_by_timesort_parameters() { 402 return new external_function_parameters( 403 array( 404 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, 0), 405 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null), 406 'aftereventid' => new external_value(PARAM_INT, 'The last seen event id', VALUE_DEFAULT, 0), 407 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20), 408 'limittononsuspendedevents' => new external_value(PARAM_BOOL, 409 'Limit the events to courses the user is not suspended in', VALUE_DEFAULT, false), 410 'userid' => new external_value(PARAM_INT, 'The user id', VALUE_DEFAULT, null), 411 'searchvalue' => new external_value(PARAM_RAW, 'The value a user wishes to search against', VALUE_DEFAULT, null) 412 ) 413 ); 414 } 415 416 /** 417 * Get calendar action events based on the timesort value. 418 * 419 * @since Moodle 3.3 420 * @param null|int $timesortfrom Events after this time (inclusive) 421 * @param null|int $timesortto Events before this time (inclusive) 422 * @param null|int $aftereventid Get events with ids greater than this one 423 * @param int $limitnum Limit the number of results to this value 424 * @param null|int $userid The user id 425 * @param string|null $searchvalue The value a user wishes to search against 426 * @return array 427 */ 428 public static function get_calendar_action_events_by_timesort($timesortfrom = 0, $timesortto = null, 429 $aftereventid = 0, $limitnum = 20, $limittononsuspendedevents = false, 430 $userid = null, ?string $searchvalue = null) { 431 global $PAGE, $USER; 432 433 $params = self::validate_parameters( 434 self::get_calendar_action_events_by_timesort_parameters(), 435 [ 436 'timesortfrom' => $timesortfrom, 437 'timesortto' => $timesortto, 438 'aftereventid' => $aftereventid, 439 'limitnum' => $limitnum, 440 'limittononsuspendedevents' => $limittononsuspendedevents, 441 'userid' => $userid, 442 'searchvalue' => $searchvalue 443 ] 444 ); 445 if ($params['userid']) { 446 $user = \core_user::get_user($params['userid']); 447 } else { 448 $user = $USER; 449 } 450 451 $context = \context_user::instance($user->id); 452 self::validate_context($context); 453 454 if ($params['userid'] && $USER->id !== $params['userid'] && !has_capability('moodle/calendar:manageentries', $context)) { 455 throw new \required_capability_exception($context, 'moodle/calendar:manageentries', 'nopermission', ''); 456 } 457 458 if (empty($params['aftereventid'])) { 459 $params['aftereventid'] = null; 460 } 461 462 $renderer = $PAGE->get_renderer('core_calendar'); 463 $events = local_api::get_action_events_by_timesort( 464 $params['timesortfrom'], 465 $params['timesortto'], 466 $params['aftereventid'], 467 $params['limitnum'], 468 $params['limittononsuspendedevents'], 469 $user, 470 clean_param($params['searchvalue'], PARAM_TEXT) 471 ); 472 473 $exportercache = new events_related_objects_cache($events); 474 $exporter = new events_exporter($events, ['cache' => $exportercache]); 475 476 return $exporter->export($renderer); 477 } 478 479 /** 480 * Returns description of method result value. 481 * 482 * @since Moodle 3.3 483 * @return external_description 484 */ 485 public static function get_calendar_action_events_by_timesort_returns() { 486 return events_exporter::get_read_structure(); 487 } 488 489 /** 490 * Returns description of method parameters. 491 * 492 * @return external_function_parameters 493 */ 494 public static function get_calendar_action_events_by_course_parameters() { 495 return new external_function_parameters( 496 array( 497 'courseid' => new external_value(PARAM_INT, 'Course id'), 498 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null), 499 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null), 500 'aftereventid' => new external_value(PARAM_INT, 'The last seen event id', VALUE_DEFAULT, 0), 501 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20), 502 'searchvalue' => new external_value(PARAM_RAW, 'The value a user wishes to search against', VALUE_DEFAULT, null) 503 ) 504 ); 505 } 506 507 /** 508 * Get calendar action events for the given course. 509 * 510 * @since Moodle 3.3 511 * @param int $courseid Only events in this course 512 * @param null|int $timesortfrom Events after this time (inclusive) 513 * @param null|int $timesortto Events before this time (inclusive) 514 * @param null|int $aftereventid Get events with ids greater than this one 515 * @param int $limitnum Limit the number of results to this value 516 * @param string|null $searchvalue The value a user wishes to search against 517 * @return array 518 */ 519 public static function get_calendar_action_events_by_course( 520 $courseid, $timesortfrom = null, $timesortto = null, $aftereventid = 0, $limitnum = 20, ?string $searchvalue = null) { 521 522 global $PAGE, $USER; 523 524 $user = null; 525 $params = self::validate_parameters( 526 self::get_calendar_action_events_by_course_parameters(), 527 [ 528 'courseid' => $courseid, 529 'timesortfrom' => $timesortfrom, 530 'timesortto' => $timesortto, 531 'aftereventid' => $aftereventid, 532 'limitnum' => $limitnum, 533 'searchvalue' => $searchvalue 534 ] 535 ); 536 $context = \context_user::instance($USER->id); 537 self::validate_context($context); 538 539 if (empty($params['aftereventid'])) { 540 $params['aftereventid'] = null; 541 } 542 543 $courses = enrol_get_my_courses('*', null, 0, [$courseid]); 544 $courses = array_values($courses); 545 546 if (empty($courses)) { 547 return []; 548 } 549 550 $course = $courses[0]; 551 $renderer = $PAGE->get_renderer('core_calendar'); 552 $events = local_api::get_action_events_by_course( 553 $course, 554 $params['timesortfrom'], 555 $params['timesortto'], 556 $params['aftereventid'], 557 $params['limitnum'], 558 clean_param($params['searchvalue'], PARAM_TEXT) 559 ); 560 561 $exportercache = new events_related_objects_cache($events, $courses); 562 $exporter = new events_exporter($events, ['cache' => $exportercache]); 563 564 return $exporter->export($renderer); 565 } 566 567 /** 568 * Returns description of method result value. 569 * 570 * @return external_description 571 */ 572 public static function get_calendar_action_events_by_course_returns() { 573 return events_exporter::get_read_structure(); 574 } 575 576 /** 577 * Returns description of method parameters. 578 * 579 * @return external_function_parameters 580 */ 581 public static function get_calendar_action_events_by_courses_parameters() { 582 return new external_function_parameters( 583 array( 584 'courseids' => new external_multiple_structure( 585 new external_value(PARAM_INT, 'Course id') 586 ), 587 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null), 588 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null), 589 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 10), 590 'searchvalue' => new external_value(PARAM_RAW, 'The value a user wishes to search against', VALUE_DEFAULT, null) 591 ) 592 ); 593 } 594 595 /** 596 * Get calendar action events for a given list of courses. 597 * 598 * @since Moodle 3.3 599 * @param array $courseids Only include events for these courses 600 * @param null|int $timesortfrom Events after this time (inclusive) 601 * @param null|int $timesortto Events before this time (inclusive) 602 * @param int $limitnum Limit the number of results per course to this value 603 * @param string|null $searchvalue The value a user wishes to search against 604 * @return array 605 */ 606 public static function get_calendar_action_events_by_courses( 607 array $courseids, $timesortfrom = null, $timesortto = null, $limitnum = 10, ?string $searchvalue = null) { 608 609 global $PAGE, $USER; 610 611 $user = null; 612 $params = self::validate_parameters( 613 self::get_calendar_action_events_by_courses_parameters(), 614 [ 615 'courseids' => $courseids, 616 'timesortfrom' => $timesortfrom, 617 'timesortto' => $timesortto, 618 'limitnum' => $limitnum, 619 'searchvalue' => $searchvalue 620 ] 621 ); 622 $context = \context_user::instance($USER->id); 623 self::validate_context($context); 624 625 if (empty($params['courseids'])) { 626 return ['groupedbycourse' => []]; 627 } 628 629 $renderer = $PAGE->get_renderer('core_calendar'); 630 $courses = enrol_get_my_courses('*', null, 0, $params['courseids']); 631 $courses = array_values($courses); 632 633 if (empty($courses)) { 634 return ['groupedbycourse' => []]; 635 } 636 637 $events = local_api::get_action_events_by_courses( 638 $courses, 639 $params['timesortfrom'], 640 $params['timesortto'], 641 $params['limitnum'], 642 clean_param($params['searchvalue'], PARAM_TEXT) 643 ); 644 645 if (empty($events)) { 646 return ['groupedbycourse' => []]; 647 } 648 649 $exportercache = new events_related_objects_cache($events, $courses); 650 $exporter = new events_grouped_by_course_exporter($events, ['cache' => $exportercache]); 651 652 return $exporter->export($renderer); 653 } 654 655 /** 656 * Returns description of method result value. 657 * 658 * @return external_description 659 */ 660 public static function get_calendar_action_events_by_courses_returns() { 661 return events_grouped_by_course_exporter::get_read_structure(); 662 } 663 664 /** 665 * Returns description of method parameters. 666 * 667 * @return external_function_parameters. 668 * @since Moodle 2.5 669 */ 670 public static function create_calendar_events_parameters() { 671 // Userid is always current user, so no need to get it from client. 672 // Module based calendar events are not allowed here. Hence no need of instance and modulename. 673 // subscription id and uuid is not allowed as this is not an ical api. 674 return new external_function_parameters( 675 array('events' => new external_multiple_structure( 676 new external_single_structure( 677 array( 678 'name' => new external_value(PARAM_TEXT, 'event name', VALUE_REQUIRED, '', NULL_NOT_ALLOWED), 679 'description' => new external_value(PARAM_RAW, 'Description', VALUE_DEFAULT, null, NULL_ALLOWED), 680 'format' => new external_format_value('description', VALUE_DEFAULT), 681 'courseid' => new external_value(PARAM_INT, 'course id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), 682 'groupid' => new external_value(PARAM_INT, 'group id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), 683 'repeats' => new external_value(PARAM_INT, 'number of repeats', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), 684 'eventtype' => new external_value(PARAM_TEXT, 'Event type', VALUE_DEFAULT, 'user', NULL_NOT_ALLOWED), 685 'timestart' => new external_value(PARAM_INT, 'timestart', VALUE_DEFAULT, time(), NULL_NOT_ALLOWED), 686 'timeduration' => new external_value(PARAM_INT, 'time duration', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), 687 'visible' => new external_value(PARAM_INT, 'visible', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED), 688 'sequence' => new external_value(PARAM_INT, 'sequence', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED), 689 ), 'event') 690 ) 691 ) 692 ); 693 } 694 695 /** 696 * Create calendar events. 697 * 698 * @param array $events A list of events to create. 699 * @return array array of events created. 700 * @since Moodle 2.5 701 * @throws moodle_exception if user doesnt have the permission to create events. 702 */ 703 public static function create_calendar_events($events) { 704 global $DB, $USER; 705 706 // Parameter validation. 707 $params = self::validate_parameters(self::create_calendar_events_parameters(), array('events' => $events)); 708 709 $transaction = $DB->start_delegated_transaction(); 710 $return = array(); 711 $warnings = array(); 712 713 foreach ($params['events'] as $event) { 714 715 // Let us set some defaults. 716 $event['userid'] = $USER->id; 717 $event['modulename'] = ''; 718 $event['instance'] = 0; 719 $event['subscriptionid'] = null; 720 $event['uuid']= ''; 721 $event['format'] = external_validate_format($event['format']); 722 if ($event['repeats'] > 0) { 723 $event['repeat'] = 1; 724 } else { 725 $event['repeat'] = 0; 726 } 727 728 $eventobj = new calendar_event($event); 729 730 // Let's check if the user is allowed to delete an event. 731 if (!calendar_add_event_allowed($eventobj)) { 732 $warnings [] = array('item' => $event['name'], 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to create this event'); 733 continue; 734 } 735 // Let's create the event. 736 $var = $eventobj->create($event); 737 $var = (array)$var->properties(); 738 if ($event['repeat']) { 739 $children = $DB->get_records('event', array('repeatid' => $var['id'])); 740 foreach ($children as $child) { 741 $return[] = (array) $child; 742 } 743 } else { 744 $return[] = $var; 745 } 746 } 747 748 // Everything done smoothly, let's commit. 749 $transaction->allow_commit(); 750 return array('events' => $return, 'warnings' => $warnings); 751 } 752 753 /** 754 * Returns description of method result value. 755 * 756 * @return external_description. 757 * @since Moodle 2.5 758 */ 759 public static function create_calendar_events_returns() { 760 return new external_single_structure( 761 array( 762 'events' => new external_multiple_structure( new external_single_structure( 763 array( 764 'id' => new external_value(PARAM_INT, 'event id'), 765 'name' => new external_value(PARAM_RAW, 'event name'), 766 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL), 767 'format' => new external_format_value('description'), 768 'courseid' => new external_value(PARAM_INT, 'course id'), 769 'groupid' => new external_value(PARAM_INT, 'group id'), 770 'userid' => new external_value(PARAM_INT, 'user id'), 771 'repeatid' => new external_value(PARAM_INT, 'repeat id', VALUE_OPTIONAL), 772 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL), 773 'instance' => new external_value(PARAM_INT, 'instance id'), 774 'eventtype' => new external_value(PARAM_TEXT, 'Event type'), 775 'timestart' => new external_value(PARAM_INT, 'timestart'), 776 'timeduration' => new external_value(PARAM_INT, 'time duration'), 777 'visible' => new external_value(PARAM_INT, 'visible'), 778 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED), 779 'sequence' => new external_value(PARAM_INT, 'sequence'), 780 'timemodified' => new external_value(PARAM_INT, 'time modified'), 781 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL), 782 ), 'event') 783 ), 784 'warnings' => new external_warnings() 785 ) 786 ); 787 } 788 789 /** 790 * Returns description of method parameters. 791 * 792 * @return external_function_parameters 793 */ 794 public static function get_calendar_event_by_id_parameters() { 795 return new external_function_parameters( 796 array( 797 'eventid' => new external_value(PARAM_INT, 'The event id to be retrieved'), 798 ) 799 ); 800 } 801 802 /** 803 * Get calendar event by id. 804 * 805 * @param int $eventid The calendar event id to be retrieved. 806 * @return array Array of event details 807 */ 808 public static function get_calendar_event_by_id($eventid) { 809 global $PAGE, $USER; 810 811 $params = self::validate_parameters(self::get_calendar_event_by_id_parameters(), ['eventid' => $eventid]); 812 $context = \context_user::instance($USER->id); 813 814 self::validate_context($context); 815 $warnings = array(); 816 817 $eventvault = event_container::get_event_vault(); 818 if ($event = $eventvault->get_event_by_id($params['eventid'])) { 819 $mapper = event_container::get_event_mapper(); 820 if (!calendar_view_event_allowed($mapper->from_event_to_legacy_event($event))) { 821 throw new moodle_exception('nopermissiontoviewcalendar', 'error'); 822 } 823 } 824 825 if (!$event) { 826 // We can't return a warning in this case because the event is not optional. 827 // We don't know the context for the event and it's not worth loading it. 828 $syscontext = context_system::instance(); 829 throw new \required_capability_exception($syscontext, 'moodle/course:view', 'nopermissions', 'error'); 830 } 831 832 $cache = new events_related_objects_cache([$event]); 833 $relatedobjects = [ 834 'context' => $cache->get_context($event), 835 'course' => $cache->get_course($event), 836 ]; 837 838 $exporter = new event_exporter($event, $relatedobjects); 839 $renderer = $PAGE->get_renderer('core_calendar'); 840 841 return array('event' => $exporter->export($renderer), 'warnings' => $warnings); 842 } 843 844 /** 845 * Returns description of method result value 846 * 847 * @return external_description 848 */ 849 public static function get_calendar_event_by_id_returns() { 850 $eventstructure = event_exporter::get_read_structure(); 851 852 return new external_single_structure(array( 853 'event' => $eventstructure, 854 'warnings' => new external_warnings() 855 ) 856 ); 857 } 858 859 /** 860 * Returns description of method parameters. 861 * 862 * @return external_function_parameters. 863 */ 864 public static function submit_create_update_form_parameters() { 865 return new external_function_parameters( 866 [ 867 'formdata' => new external_value(PARAM_RAW, 'The data from the event form'), 868 ] 869 ); 870 } 871 872 /** 873 * Handles the event form submission. 874 * 875 * @param string $formdata The event form data in a URI encoded param string 876 * @return array The created or modified event 877 * @throws moodle_exception 878 */ 879 public static function submit_create_update_form($formdata) { 880 global $USER, $PAGE, $CFG; 881 require_once($CFG->libdir."/filelib.php"); 882 883 // Parameter validation. 884 $params = self::validate_parameters(self::submit_create_update_form_parameters(), ['formdata' => $formdata]); 885 $context = \context_user::instance($USER->id); 886 $data = []; 887 888 self::validate_context($context); 889 parse_str($params['formdata'], $data); 890 891 if (WS_SERVER) { 892 // Request via WS, ignore sesskey checks in form library. 893 $USER->ignoresesskey = true; 894 } 895 896 $eventtype = isset($data['eventtype']) ? $data['eventtype'] : null; 897 $coursekey = ($eventtype == 'group') ? 'groupcourseid' : 'courseid'; 898 $courseid = (!empty($data[$coursekey])) ? $data[$coursekey] : null; 899 $editoroptions = \core_calendar\local\event\forms\create::build_editor_options($context); 900 $formoptions = ['editoroptions' => $editoroptions, 'courseid' => $courseid]; 901 $formoptions['eventtypes'] = calendar_get_allowed_event_types($courseid); 902 if ($courseid) { 903 require_once($CFG->libdir . '/grouplib.php'); 904 $groupcoursedata = groups_get_course_data($courseid); 905 if (!empty($groupcoursedata->groups)) { 906 $formoptions['groups'] = []; 907 foreach ($groupcoursedata->groups as $groupid => $groupdata) { 908 $formoptions['groups'][$groupid] = $groupdata->name; 909 } 910 } 911 } 912 913 if (!empty($data['id'])) { 914 $eventid = clean_param($data['id'], PARAM_INT); 915 $legacyevent = calendar_event::load($eventid); 916 $legacyevent->count_repeats(); 917 $formoptions['event'] = $legacyevent; 918 $mform = new update_event_form(null, $formoptions, 'post', '', null, true, $data); 919 } else { 920 $legacyevent = null; 921 $mform = new create_event_form(null, $formoptions, 'post', '', null, true, $data); 922 } 923 924 if ($validateddata = $mform->get_data()) { 925 $formmapper = new create_update_form_mapper(); 926 $properties = $formmapper->from_data_to_event_properties($validateddata); 927 928 if (is_null($legacyevent)) { 929 $legacyevent = new \calendar_event($properties); 930 // Need to do this in order to initialise the description 931 // property which then triggers the update function below 932 // to set the appropriate default properties on the event. 933 $properties = $legacyevent->properties(true); 934 } 935 936 if (!calendar_edit_event_allowed($legacyevent, true)) { 937 throw new \moodle_exception('nopermissiontoupdatecalendar'); 938 } 939 940 $legacyevent->update($properties); 941 $eventcontext = $legacyevent->context; 942 943 file_remove_editor_orphaned_files($validateddata->description); 944 945 // Take any files added to the description draft file area and 946 // convert them into the proper event description file area. Also 947 // parse the description text and replace the URLs to the draft files 948 // with the @@PLUGIN_FILE@@ placeholder to be persisted in the DB. 949 $description = file_save_draft_area_files( 950 $validateddata->description['itemid'], 951 $eventcontext->id, 952 'calendar', 953 'event_description', 954 $legacyevent->id, 955 create_event_form::build_editor_options($eventcontext), 956 $validateddata->description['text'] 957 ); 958 959 // If draft files were found then we need to save the new 960 // description value. 961 if ($description != $validateddata->description['text']) { 962 $properties->id = $legacyevent->id; 963 $properties->description = $description; 964 $legacyevent->update($properties); 965 } 966 967 $eventmapper = event_container::get_event_mapper(); 968 $event = $eventmapper->from_legacy_event_to_event($legacyevent); 969 $cache = new events_related_objects_cache([$event]); 970 $relatedobjects = [ 971 'context' => $cache->get_context($event), 972 'course' => $cache->get_course($event), 973 ]; 974 $exporter = new event_exporter($event, $relatedobjects); 975 $renderer = $PAGE->get_renderer('core_calendar'); 976 977 return [ 'event' => $exporter->export($renderer) ]; 978 } else { 979 return [ 'validationerror' => true ]; 980 } 981 } 982 983 /** 984 * Returns description of method result value. 985 * 986 * @return external_description. 987 */ 988 public static function submit_create_update_form_returns() { 989 $eventstructure = event_exporter::get_read_structure(); 990 $eventstructure->required = VALUE_OPTIONAL; 991 992 return new external_single_structure( 993 array( 994 'event' => $eventstructure, 995 'validationerror' => new external_value(PARAM_BOOL, 'Invalid form data', VALUE_DEFAULT, false), 996 ) 997 ); 998 } 999 1000 /** 1001 * Get data for the monthly calendar view. 1002 * 1003 * @param int $year The year to be shown 1004 * @param int $month The month to be shown 1005 * @param int $courseid The course to be included 1006 * @param int $categoryid The category to be included 1007 * @param bool $includenavigation Whether to include navigation 1008 * @param bool $mini Whether to return the mini month view or not 1009 * @param int $day The day we want to keep as the current day 1010 * @param string|null $view The view mode for the calendar. 1011 * @return array 1012 */ 1013 public static function get_calendar_monthly_view($year, $month, $courseid, $categoryid, $includenavigation, $mini, $day, 1014 ?string $view = null) { 1015 global $USER, $PAGE; 1016 1017 // Parameter validation. 1018 $params = self::validate_parameters(self::get_calendar_monthly_view_parameters(), [ 1019 'year' => $year, 1020 'month' => $month, 1021 'courseid' => $courseid, 1022 'categoryid' => $categoryid, 1023 'includenavigation' => $includenavigation, 1024 'mini' => $mini, 1025 'day' => $day, 1026 'view' => $view, 1027 ]); 1028 1029 $context = \context_user::instance($USER->id); 1030 self::validate_context($context); 1031 $PAGE->set_url('/calendar/'); 1032 1033 $type = \core_calendar\type_factory::get_calendar_instance(); 1034 1035 $time = $type->convert_to_timestamp($params['year'], $params['month'], $params['day']); 1036 $calendar = \calendar_information::create($time, $params['courseid'], $params['categoryid']); 1037 self::validate_context($calendar->context); 1038 1039 $view = $params['view'] ?? ($params['mini'] ? 'mini' : 'month'); 1040 list($data, $template) = calendar_get_view($calendar, $view, $params['includenavigation']); 1041 1042 return $data; 1043 } 1044 1045 /** 1046 * Returns description of method parameters. 1047 * 1048 * @return external_function_parameters 1049 */ 1050 public static function get_calendar_monthly_view_parameters() { 1051 return new external_function_parameters( 1052 [ 1053 'year' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED), 1054 'month' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED), 1055 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), 1056 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), 1057 'includenavigation' => new external_value( 1058 PARAM_BOOL, 1059 'Whether to show course navigation', 1060 VALUE_DEFAULT, 1061 true, 1062 NULL_ALLOWED 1063 ), 1064 'mini' => new external_value( 1065 PARAM_BOOL, 1066 'Whether to return the mini month view or not', 1067 VALUE_DEFAULT, 1068 false, 1069 NULL_ALLOWED 1070 ), 1071 'day' => new external_value(PARAM_INT, 'Day to be viewed', VALUE_DEFAULT, 1), 1072 'view' => new external_value(PARAM_ALPHA, 'The view mode of the calendar', VALUE_DEFAULT, 'month', NULL_ALLOWED), 1073 ] 1074 ); 1075 } 1076 1077 /** 1078 * Returns description of method result value. 1079 * 1080 * @return external_description 1081 */ 1082 public static function get_calendar_monthly_view_returns() { 1083 return \core_calendar\external\month_exporter::get_read_structure(); 1084 } 1085 1086 /** 1087 * Get data for the daily calendar view. 1088 * 1089 * @param int $year The year to be shown 1090 * @param int $month The month to be shown 1091 * @param int $day The day to be shown 1092 * @param int $courseid The course to be included 1093 * @return array 1094 */ 1095 public static function get_calendar_day_view($year, $month, $day, $courseid, $categoryid) { 1096 global $DB, $USER, $PAGE; 1097 1098 // Parameter validation. 1099 $params = self::validate_parameters(self::get_calendar_day_view_parameters(), [ 1100 'year' => $year, 1101 'month' => $month, 1102 'day' => $day, 1103 'courseid' => $courseid, 1104 'categoryid' => $categoryid, 1105 ]); 1106 1107 $context = \context_user::instance($USER->id); 1108 self::validate_context($context); 1109 1110 $type = \core_calendar\type_factory::get_calendar_instance(); 1111 1112 $time = $type->convert_to_timestamp($params['year'], $params['month'], $params['day']); 1113 $calendar = \calendar_information::create($time, $params['courseid'], $params['categoryid']); 1114 self::validate_context($calendar->context); 1115 1116 list($data, $template) = calendar_get_view($calendar, 'day'); 1117 1118 return $data; 1119 } 1120 1121 /** 1122 * Returns description of method parameters. 1123 * 1124 * @return external_function_parameters 1125 */ 1126 public static function get_calendar_day_view_parameters() { 1127 return new external_function_parameters( 1128 [ 1129 'year' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED), 1130 'month' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED), 1131 'day' => new external_value(PARAM_INT, 'Day to be viewed', VALUE_REQUIRED), 1132 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), 1133 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), 1134 ] 1135 ); 1136 } 1137 1138 /** 1139 * Returns description of method result value. 1140 * 1141 * @return external_description 1142 */ 1143 public static function get_calendar_day_view_returns() { 1144 return \core_calendar\external\calendar_day_exporter::get_read_structure(); 1145 } 1146 1147 1148 /** 1149 * Returns description of method parameters. 1150 * 1151 * @return external_function_parameters 1152 */ 1153 public static function update_event_start_day_parameters() { 1154 return new external_function_parameters( 1155 [ 1156 'eventid' => new external_value(PARAM_INT, 'Id of event to be updated', VALUE_REQUIRED), 1157 'daytimestamp' => new external_value(PARAM_INT, 'Timestamp for the new start day', VALUE_REQUIRED), 1158 ] 1159 ); 1160 } 1161 1162 /** 1163 * Change the start day for the given calendar event to the day that 1164 * corresponds with the provided timestamp. 1165 * 1166 * The timestamp only needs to be anytime within the desired day as only 1167 * the date data is extracted from it. 1168 * 1169 * The event's original time of day is maintained, only the date is shifted. 1170 * 1171 * @param int $eventid Id of event to be updated 1172 * @param int $daytimestamp Timestamp for the new start day 1173 * @return array 1174 */ 1175 public static function update_event_start_day($eventid, $daytimestamp) { 1176 global $USER, $PAGE; 1177 1178 // Parameter validation. 1179 $params = self::validate_parameters(self::update_event_start_day_parameters(), [ 1180 'eventid' => $eventid, 1181 'daytimestamp' => $daytimestamp, 1182 ]); 1183 1184 $vault = event_container::get_event_vault(); 1185 $mapper = event_container::get_event_mapper(); 1186 $event = $vault->get_event_by_id($eventid); 1187 1188 if (!$event) { 1189 throw new \moodle_exception('Unable to find event with id ' . $eventid); 1190 } 1191 1192 $legacyevent = $mapper->from_event_to_legacy_event($event); 1193 1194 if (!calendar_edit_event_allowed($legacyevent, true)) { 1195 throw new \moodle_exception('nopermissiontoupdatecalendar'); 1196 } 1197 1198 self::validate_context($legacyevent->context); 1199 1200 $newdate = usergetdate($daytimestamp); 1201 $startdatestring = implode('-', [$newdate['year'], $newdate['mon'], $newdate['mday']]); 1202 $startdate = new DateTimeImmutable($startdatestring); 1203 $event = local_api::update_event_start_day($event, $startdate); 1204 $cache = new events_related_objects_cache([$event]); 1205 $relatedobjects = [ 1206 'context' => $cache->get_context($event), 1207 'course' => $cache->get_course($event), 1208 ]; 1209 $exporter = new event_exporter($event, $relatedobjects); 1210 $renderer = $PAGE->get_renderer('core_calendar'); 1211 1212 return array('event' => $exporter->export($renderer)); 1213 } 1214 1215 /** 1216 * Returns description of method result value. 1217 * 1218 * @return external_description 1219 */ 1220 public static function update_event_start_day_returns() { 1221 return new external_single_structure( 1222 array( 1223 'event' => event_exporter::get_read_structure() 1224 ) 1225 ); 1226 } 1227 1228 /** 1229 * Get data for the monthly calendar view. 1230 * 1231 * @param int $courseid The course to be included 1232 * @param int $categoryid The category to be included 1233 * @return array 1234 */ 1235 public static function get_calendar_upcoming_view($courseid, $categoryid) { 1236 global $DB, $USER, $PAGE; 1237 1238 // Parameter validation. 1239 $params = self::validate_parameters(self::get_calendar_upcoming_view_parameters(), [ 1240 'courseid' => $courseid, 1241 'categoryid' => $categoryid, 1242 ]); 1243 1244 $context = \context_user::instance($USER->id); 1245 self::validate_context($context); 1246 $PAGE->set_url('/calendar/'); 1247 1248 $calendar = \calendar_information::create(time(), $params['courseid'], $params['categoryid']); 1249 self::validate_context($calendar->context); 1250 1251 list($data, $template) = calendar_get_view($calendar, 'upcoming'); 1252 1253 return $data; 1254 } 1255 1256 /** 1257 * Returns description of method parameters. 1258 * 1259 * @return external_function_parameters 1260 */ 1261 public static function get_calendar_upcoming_view_parameters() { 1262 return new external_function_parameters( 1263 [ 1264 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), 1265 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), 1266 ] 1267 ); 1268 } 1269 1270 /** 1271 * Returns description of method result value. 1272 * 1273 * @return external_description 1274 */ 1275 public static function get_calendar_upcoming_view_returns() { 1276 return \core_calendar\external\calendar_upcoming_exporter::get_read_structure(); 1277 } 1278 1279 1280 /** 1281 * Returns description of method parameters. 1282 * 1283 * @return external_function_parameters. 1284 * @since Moodle 3.7 1285 */ 1286 public static function get_calendar_access_information_parameters() { 1287 return new external_function_parameters( 1288 [ 1289 'courseid' => new external_value(PARAM_INT, 'Course to check, empty for site calendar events.', VALUE_DEFAULT, 0), 1290 ] 1291 ); 1292 } 1293 1294 /** 1295 * Convenience function to retrieve some permissions information for the given course calendar. 1296 * 1297 * @param int $courseid Course to check, empty for site. 1298 * @return array The access information 1299 * @throws moodle_exception 1300 * @since Moodle 3.7 1301 */ 1302 public static function get_calendar_access_information($courseid = 0) { 1303 1304 $params = self::validate_parameters(self::get_calendar_access_information_parameters(), ['courseid' => $courseid]); 1305 1306 if (empty($params['courseid']) || $params['courseid'] == SITEID) { 1307 $context = \context_system::instance(); 1308 } else { 1309 $context = \context_course::instance($params['courseid']); 1310 } 1311 1312 self::validate_context($context); 1313 1314 return [ 1315 'canmanageentries' => has_capability('moodle/calendar:manageentries', $context), 1316 'canmanageownentries' => has_capability('moodle/calendar:manageownentries', $context), 1317 'canmanagegroupentries' => has_capability('moodle/calendar:managegroupentries', $context), 1318 'warnings' => [], 1319 ]; 1320 } 1321 1322 /** 1323 * Returns description of method result value. 1324 * 1325 * @return external_description. 1326 * @since Moodle 3.7 1327 */ 1328 public static function get_calendar_access_information_returns() { 1329 1330 return new external_single_structure( 1331 [ 1332 'canmanageentries' => new external_value(PARAM_BOOL, 'Whether the user can manage entries.'), 1333 'canmanageownentries' => new external_value(PARAM_BOOL, 'Whether the user can manage its own entries.'), 1334 'canmanagegroupentries' => new external_value(PARAM_BOOL, 'Whether the user can manage group entries.'), 1335 'warnings' => new external_warnings(), 1336 ] 1337 ); 1338 } 1339 1340 /** 1341 * Returns description of method parameters. 1342 * 1343 * @return external_function_parameters. 1344 * @since Moodle 3.7 1345 */ 1346 public static function get_allowed_event_types_parameters() { 1347 return new external_function_parameters( 1348 [ 1349 'courseid' => new external_value(PARAM_INT, 'Course to check, empty for site.', VALUE_DEFAULT, 0), 1350 ] 1351 ); 1352 } 1353 1354 /** 1355 * Get the type of events a user can create in the given course. 1356 * 1357 * @param int $courseid Course to check, empty for site. 1358 * @return array The types allowed 1359 * @throws moodle_exception 1360 * @since Moodle 3.7 1361 */ 1362 public static function get_allowed_event_types($courseid = 0) { 1363 1364 $params = self::validate_parameters(self::get_allowed_event_types_parameters(), ['courseid' => $courseid]); 1365 1366 if (empty($params['courseid']) || $params['courseid'] == SITEID) { 1367 $context = \context_system::instance(); 1368 } else { 1369 $context = \context_course::instance($params['courseid']); 1370 } 1371 1372 self::validate_context($context); 1373 1374 $allowedeventtypes = array_filter(calendar_get_allowed_event_types($params['courseid'])); 1375 1376 return [ 1377 'allowedeventtypes' => array_keys($allowedeventtypes), 1378 'warnings' => [], 1379 ]; 1380 } 1381 1382 /** 1383 * Returns description of method result value. 1384 * 1385 * @return external_description. 1386 * @since Moodle 3.7 1387 */ 1388 public static function get_allowed_event_types_returns() { 1389 1390 return new external_single_structure( 1391 [ 1392 'allowedeventtypes' => new external_multiple_structure( 1393 new external_value(PARAM_NOTAGS, 'Allowed event types to be created in the given course.') 1394 ), 1395 'warnings' => new external_warnings(), 1396 ] 1397 ); 1398 } 1399 1400 /** 1401 * Convert the specified dates into unix timestamps. 1402 * 1403 * @param array $datetimes Array of arrays containing date time details, each in the format: 1404 * ['year' => a, 'month' => b, 'day' => c, 1405 * 'hour' => d (optional), 'minute' => e (optional), 'key' => 'x' (optional)] 1406 * @return array Provided array of dates converted to unix timestamps 1407 * @throws moodle_exception If one or more of the dates provided does not convert to a valid timestamp. 1408 */ 1409 public static function get_timestamps($datetimes) { 1410 $params = self::validate_parameters(self::get_timestamps_parameters(), ['data' => $datetimes]); 1411 1412 $type = \core_calendar\type_factory::get_calendar_instance(); 1413 $timestamps = ['timestamps' => []]; 1414 1415 foreach ($params['data'] as $key => $datetime) { 1416 $hour = $datetime['hour'] ?? 0; 1417 $minute = $datetime['minute'] ?? 0; 1418 1419 try { 1420 $timestamp = $type->convert_to_timestamp( 1421 $datetime['year'], $datetime['month'], $datetime['day'], $hour, $minute); 1422 1423 $timestamps['timestamps'][] = [ 1424 'key' => $datetime['key'] ?? $key, 1425 'timestamp' => $timestamp, 1426 ]; 1427 1428 } catch (Exception $e) { 1429 throw new moodle_exception('One or more of the dates provided were invalid'); 1430 } 1431 } 1432 1433 return $timestamps; 1434 } 1435 1436 /** 1437 * Describes the parameters for get_timestamps. 1438 * 1439 * @return external_function_parameters 1440 */ 1441 public static function get_timestamps_parameters() { 1442 return new external_function_parameters ([ 1443 'data' => new external_multiple_structure( 1444 new external_single_structure( 1445 [ 1446 'key' => new external_value(PARAM_ALPHANUMEXT, 'key', VALUE_OPTIONAL), 1447 'year' => new external_value(PARAM_INT, 'year'), 1448 'month' => new external_value(PARAM_INT, 'month'), 1449 'day' => new external_value(PARAM_INT, 'day'), 1450 'hour' => new external_value(PARAM_INT, 'hour', VALUE_OPTIONAL), 1451 'minute' => new external_value(PARAM_INT, 'minute', VALUE_OPTIONAL), 1452 ] 1453 ) 1454 ) 1455 ]); 1456 } 1457 1458 /** 1459 * Describes the timestamps return format. 1460 * 1461 * @return external_single_structure 1462 */ 1463 public static function get_timestamps_returns() { 1464 return new external_single_structure( 1465 [ 1466 'timestamps' => new external_multiple_structure( 1467 new external_single_structure( 1468 [ 1469 'key' => new external_value(PARAM_ALPHANUMEXT, 'Timestamp key'), 1470 'timestamp' => new external_value(PARAM_INT, 'Unix timestamp'), 1471 ] 1472 ) 1473 ) 1474 ] 1475 ); 1476 } 1477 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body