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 28defined('MOODLE_INTERNAL') || die; 29 30require_once("$CFG->libdir/externallib.php"); 31require_once($CFG->dirroot . '/calendar/lib.php'); 32 33use \core_calendar\local\api as local_api; 34use \core_calendar\local\event\container as event_container; 35use \core_calendar\local\event\forms\create as create_event_form; 36use \core_calendar\local\event\forms\update as update_event_form; 37use \core_calendar\local\event\mappers\create_update_form_mapper; 38use \core_calendar\external\event_exporter; 39use \core_calendar\external\events_exporter; 40use \core_calendar\external\events_grouped_by_course_exporter; 41use \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 */ 52class 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 ) 412 ); 413 } 414 415 /** 416 * Get calendar action events based on the timesort value. 417 * 418 * @since Moodle 3.3 419 * @param null|int $timesortfrom Events after this time (inclusive) 420 * @param null|int $timesortto Events before this time (inclusive) 421 * @param null|int $aftereventid Get events with ids greater than this one 422 * @param int $limitnum Limit the number of results to this value 423 * @param null|int $userid The user id 424 * @return array 425 */ 426 public static function get_calendar_action_events_by_timesort($timesortfrom = 0, $timesortto = null, 427 $aftereventid = 0, $limitnum = 20, $limittononsuspendedevents = false, 428 $userid = null) { 429 global $PAGE, $USER; 430 431 $params = self::validate_parameters( 432 self::get_calendar_action_events_by_timesort_parameters(), 433 [ 434 'timesortfrom' => $timesortfrom, 435 'timesortto' => $timesortto, 436 'aftereventid' => $aftereventid, 437 'limitnum' => $limitnum, 438 'limittononsuspendedevents' => $limittononsuspendedevents, 439 'userid' => $userid, 440 ] 441 ); 442 if ($params['userid']) { 443 $user = \core_user::get_user($params['userid']); 444 } else { 445 $user = $USER; 446 } 447 448 $context = \context_user::instance($user->id); 449 self::validate_context($context); 450 451 if ($params['userid'] && $USER->id !== $params['userid'] && !has_capability('moodle/calendar:manageentries', $context)) { 452 throw new \required_capability_exception($context, 'moodle/calendar:manageentries', 'nopermission', ''); 453 } 454 455 if (empty($params['aftereventid'])) { 456 $params['aftereventid'] = null; 457 } 458 459 $renderer = $PAGE->get_renderer('core_calendar'); 460 $events = local_api::get_action_events_by_timesort( 461 $params['timesortfrom'], 462 $params['timesortto'], 463 $params['aftereventid'], 464 $params['limitnum'], 465 $params['limittononsuspendedevents'], 466 $user 467 ); 468 469 $exportercache = new events_related_objects_cache($events); 470 $exporter = new events_exporter($events, ['cache' => $exportercache]); 471 472 return $exporter->export($renderer); 473 } 474 475 /** 476 * Returns description of method result value. 477 * 478 * @since Moodle 3.3 479 * @return external_description 480 */ 481 public static function get_calendar_action_events_by_timesort_returns() { 482 return events_exporter::get_read_structure(); 483 } 484 485 /** 486 * Returns description of method parameters. 487 * 488 * @return external_function_parameters 489 */ 490 public static function get_calendar_action_events_by_course_parameters() { 491 return new external_function_parameters( 492 array( 493 'courseid' => new external_value(PARAM_INT, 'Course id'), 494 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null), 495 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null), 496 'aftereventid' => new external_value(PARAM_INT, 'The last seen event id', VALUE_DEFAULT, 0), 497 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20) 498 ) 499 ); 500 } 501 502 /** 503 * Get calendar action events for the given course. 504 * 505 * @since Moodle 3.3 506 * @param int $courseid Only events in this course 507 * @param null|int $timesortfrom Events after this time (inclusive) 508 * @param null|int $timesortto Events before this time (inclusive) 509 * @param null|int $aftereventid Get events with ids greater than this one 510 * @param int $limitnum Limit the number of results to this value 511 * @return array 512 */ 513 public static function get_calendar_action_events_by_course( 514 $courseid, $timesortfrom = null, $timesortto = null, $aftereventid = 0, $limitnum = 20) { 515 516 global $PAGE, $USER; 517 518 $user = null; 519 $params = self::validate_parameters( 520 self::get_calendar_action_events_by_course_parameters(), 521 [ 522 'courseid' => $courseid, 523 'timesortfrom' => $timesortfrom, 524 'timesortto' => $timesortto, 525 'aftereventid' => $aftereventid, 526 'limitnum' => $limitnum, 527 ] 528 ); 529 $context = \context_user::instance($USER->id); 530 self::validate_context($context); 531 532 if (empty($params['aftereventid'])) { 533 $params['aftereventid'] = null; 534 } 535 536 $courses = enrol_get_my_courses('*', null, 0, [$courseid]); 537 $courses = array_values($courses); 538 539 if (empty($courses)) { 540 return []; 541 } 542 543 $course = $courses[0]; 544 $renderer = $PAGE->get_renderer('core_calendar'); 545 $events = local_api::get_action_events_by_course( 546 $course, 547 $params['timesortfrom'], 548 $params['timesortto'], 549 $params['aftereventid'], 550 $params['limitnum'] 551 ); 552 553 $exportercache = new events_related_objects_cache($events, $courses); 554 $exporter = new events_exporter($events, ['cache' => $exportercache]); 555 556 return $exporter->export($renderer); 557 } 558 559 /** 560 * Returns description of method result value. 561 * 562 * @return external_description 563 */ 564 public static function get_calendar_action_events_by_course_returns() { 565 return events_exporter::get_read_structure(); 566 } 567 568 /** 569 * Returns description of method parameters. 570 * 571 * @return external_function_parameters 572 */ 573 public static function get_calendar_action_events_by_courses_parameters() { 574 return new external_function_parameters( 575 array( 576 'courseids' => new external_multiple_structure( 577 new external_value(PARAM_INT, 'Course id') 578 ), 579 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null), 580 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null), 581 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 10) 582 ) 583 ); 584 } 585 586 /** 587 * Get calendar action events for a given list of courses. 588 * 589 * @since Moodle 3.3 590 * @param array $courseids Only include events for these courses 591 * @param null|int $timesortfrom Events after this time (inclusive) 592 * @param null|int $timesortto Events before this time (inclusive) 593 * @param int $limitnum Limit the number of results per course to this value 594 * @return array 595 */ 596 public static function get_calendar_action_events_by_courses( 597 array $courseids, $timesortfrom = null, $timesortto = null, $limitnum = 10) { 598 599 global $PAGE, $USER; 600 601 $user = null; 602 $params = self::validate_parameters( 603 self::get_calendar_action_events_by_courses_parameters(), 604 [ 605 'courseids' => $courseids, 606 'timesortfrom' => $timesortfrom, 607 'timesortto' => $timesortto, 608 'limitnum' => $limitnum, 609 ] 610 ); 611 $context = \context_user::instance($USER->id); 612 self::validate_context($context); 613 614 if (empty($params['courseids'])) { 615 return ['groupedbycourse' => []]; 616 } 617 618 $renderer = $PAGE->get_renderer('core_calendar'); 619 $courses = enrol_get_my_courses('*', null, 0, $params['courseids']); 620 $courses = array_values($courses); 621 622 if (empty($courses)) { 623 return ['groupedbycourse' => []]; 624 } 625 626 $events = local_api::get_action_events_by_courses( 627 $courses, 628 $params['timesortfrom'], 629 $params['timesortto'], 630 $params['limitnum'] 631 ); 632 633 if (empty($events)) { 634 return ['groupedbycourse' => []]; 635 } 636 637 $exportercache = new events_related_objects_cache($events, $courses); 638 $exporter = new events_grouped_by_course_exporter($events, ['cache' => $exportercache]); 639 640 return $exporter->export($renderer); 641 } 642 643 /** 644 * Returns description of method result value. 645 * 646 * @return external_description 647 */ 648 public static function get_calendar_action_events_by_courses_returns() { 649 return events_grouped_by_course_exporter::get_read_structure(); 650 } 651 652 /** 653 * Returns description of method parameters. 654 * 655 * @return external_function_parameters. 656 * @since Moodle 2.5 657 */ 658 public static function create_calendar_events_parameters() { 659 // Userid is always current user, so no need to get it from client. 660 // Module based calendar events are not allowed here. Hence no need of instance and modulename. 661 // subscription id and uuid is not allowed as this is not an ical api. 662 return new external_function_parameters( 663 array('events' => new external_multiple_structure( 664 new external_single_structure( 665 array( 666 'name' => new external_value(PARAM_TEXT, 'event name', VALUE_REQUIRED, '', NULL_NOT_ALLOWED), 667 'description' => new external_value(PARAM_RAW, 'Description', VALUE_DEFAULT, null, NULL_ALLOWED), 668 'format' => new external_format_value('description', VALUE_DEFAULT), 669 'courseid' => new external_value(PARAM_INT, 'course id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), 670 'groupid' => new external_value(PARAM_INT, 'group id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), 671 'repeats' => new external_value(PARAM_INT, 'number of repeats', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), 672 'eventtype' => new external_value(PARAM_TEXT, 'Event type', VALUE_DEFAULT, 'user', NULL_NOT_ALLOWED), 673 'timestart' => new external_value(PARAM_INT, 'timestart', VALUE_DEFAULT, time(), NULL_NOT_ALLOWED), 674 'timeduration' => new external_value(PARAM_INT, 'time duration', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), 675 'visible' => new external_value(PARAM_INT, 'visible', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED), 676 'sequence' => new external_value(PARAM_INT, 'sequence', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED), 677 ), 'event') 678 ) 679 ) 680 ); 681 } 682 683 /** 684 * Create calendar events. 685 * 686 * @param array $events A list of events to create. 687 * @return array array of events created. 688 * @since Moodle 2.5 689 * @throws moodle_exception if user doesnt have the permission to create events. 690 */ 691 public static function create_calendar_events($events) { 692 global $DB, $USER; 693 694 // Parameter validation. 695 $params = self::validate_parameters(self::create_calendar_events_parameters(), array('events' => $events)); 696 697 $transaction = $DB->start_delegated_transaction(); 698 $return = array(); 699 $warnings = array(); 700 701 foreach ($params['events'] as $event) { 702 703 // Let us set some defaults. 704 $event['userid'] = $USER->id; 705 $event['modulename'] = ''; 706 $event['instance'] = 0; 707 $event['subscriptionid'] = null; 708 $event['uuid']= ''; 709 $event['format'] = external_validate_format($event['format']); 710 if ($event['repeats'] > 0) { 711 $event['repeat'] = 1; 712 } else { 713 $event['repeat'] = 0; 714 } 715 716 $eventobj = new calendar_event($event); 717 718 // Let's check if the user is allowed to delete an event. 719 if (!calendar_add_event_allowed($eventobj)) { 720 $warnings [] = array('item' => $event['name'], 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to create this event'); 721 continue; 722 } 723 // Let's create the event. 724 $var = $eventobj->create($event); 725 $var = (array)$var->properties(); 726 if ($event['repeat']) { 727 $children = $DB->get_records('event', array('repeatid' => $var['id'])); 728 foreach ($children as $child) { 729 $return[] = (array) $child; 730 } 731 } else { 732 $return[] = $var; 733 } 734 } 735 736 // Everything done smoothly, let's commit. 737 $transaction->allow_commit(); 738 return array('events' => $return, 'warnings' => $warnings); 739 } 740 741 /** 742 * Returns description of method result value. 743 * 744 * @return external_description. 745 * @since Moodle 2.5 746 */ 747 public static function create_calendar_events_returns() { 748 return new external_single_structure( 749 array( 750 'events' => new external_multiple_structure( new external_single_structure( 751 array( 752 'id' => new external_value(PARAM_INT, 'event id'), 753 'name' => new external_value(PARAM_RAW, 'event name'), 754 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL), 755 'format' => new external_format_value('description'), 756 'courseid' => new external_value(PARAM_INT, 'course id'), 757 'groupid' => new external_value(PARAM_INT, 'group id'), 758 'userid' => new external_value(PARAM_INT, 'user id'), 759 'repeatid' => new external_value(PARAM_INT, 'repeat id', VALUE_OPTIONAL), 760 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL), 761 'instance' => new external_value(PARAM_INT, 'instance id'), 762 'eventtype' => new external_value(PARAM_TEXT, 'Event type'), 763 'timestart' => new external_value(PARAM_INT, 'timestart'), 764 'timeduration' => new external_value(PARAM_INT, 'time duration'), 765 'visible' => new external_value(PARAM_INT, 'visible'), 766 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED), 767 'sequence' => new external_value(PARAM_INT, 'sequence'), 768 'timemodified' => new external_value(PARAM_INT, 'time modified'), 769 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL), 770 ), 'event') 771 ), 772 'warnings' => new external_warnings() 773 ) 774 ); 775 } 776 777 /** 778 * Returns description of method parameters. 779 * 780 * @return external_function_parameters 781 */ 782 public static function get_calendar_event_by_id_parameters() { 783 return new external_function_parameters( 784 array( 785 'eventid' => new external_value(PARAM_INT, 'The event id to be retrieved'), 786 ) 787 ); 788 } 789 790 /** 791 * Get calendar event by id. 792 * 793 * @param int $eventid The calendar event id to be retrieved. 794 * @return array Array of event details 795 */ 796 public static function get_calendar_event_by_id($eventid) { 797 global $PAGE, $USER; 798 799 $params = self::validate_parameters(self::get_calendar_event_by_id_parameters(), ['eventid' => $eventid]); 800 $context = \context_user::instance($USER->id); 801 802 self::validate_context($context); 803 $warnings = array(); 804 805 $eventvault = event_container::get_event_vault(); 806 if ($event = $eventvault->get_event_by_id($eventid)) { 807 $mapper = event_container::get_event_mapper(); 808 if (!calendar_view_event_allowed($mapper->from_event_to_legacy_event($event))) { 809 $event = null; 810 } 811 } 812 813 if (!$event) { 814 // We can't return a warning in this case because the event is not optional. 815 // We don't know the context for the event and it's not worth loading it. 816 $syscontext = context_system::instance(); 817 throw new \required_capability_exception($syscontext, 'moodle/course:view', 'nopermission', ''); 818 } 819 820 $cache = new events_related_objects_cache([$event]); 821 $relatedobjects = [ 822 'context' => $cache->get_context($event), 823 'course' => $cache->get_course($event), 824 ]; 825 826 $exporter = new event_exporter($event, $relatedobjects); 827 $renderer = $PAGE->get_renderer('core_calendar'); 828 829 return array('event' => $exporter->export($renderer), 'warnings' => $warnings); 830 } 831 832 /** 833 * Returns description of method result value 834 * 835 * @return external_description 836 */ 837 public static function get_calendar_event_by_id_returns() { 838 $eventstructure = event_exporter::get_read_structure(); 839 840 return new external_single_structure(array( 841 'event' => $eventstructure, 842 'warnings' => new external_warnings() 843 ) 844 ); 845 } 846 847 /** 848 * Returns description of method parameters. 849 * 850 * @return external_function_parameters. 851 */ 852 public static function submit_create_update_form_parameters() { 853 return new external_function_parameters( 854 [ 855 'formdata' => new external_value(PARAM_RAW, 'The data from the event form'), 856 ] 857 ); 858 } 859 860 /** 861 * Handles the event form submission. 862 * 863 * @param string $formdata The event form data in a URI encoded param string 864 * @return array The created or modified event 865 * @throws moodle_exception 866 */ 867 public static function submit_create_update_form($formdata) { 868 global $USER, $PAGE, $CFG; 869 require_once($CFG->libdir."/filelib.php"); 870 871 // Parameter validation. 872 $params = self::validate_parameters(self::submit_create_update_form_parameters(), ['formdata' => $formdata]); 873 $context = \context_user::instance($USER->id); 874 $data = []; 875 876 self::validate_context($context); 877 parse_str($params['formdata'], $data); 878 879 if (WS_SERVER) { 880 // Request via WS, ignore sesskey checks in form library. 881 $USER->ignoresesskey = true; 882 } 883 884 $eventtype = isset($data['eventtype']) ? $data['eventtype'] : null; 885 $coursekey = ($eventtype == 'group') ? 'groupcourseid' : 'courseid'; 886 $courseid = (!empty($data[$coursekey])) ? $data[$coursekey] : null; 887 $editoroptions = \core_calendar\local\event\forms\create::build_editor_options($context); 888 $formoptions = ['editoroptions' => $editoroptions, 'courseid' => $courseid]; 889 $formoptions['eventtypes'] = calendar_get_allowed_event_types($courseid); 890 if ($courseid) { 891 require_once($CFG->libdir . '/grouplib.php'); 892 $groupcoursedata = groups_get_course_data($courseid); 893 if (!empty($groupcoursedata->groups)) { 894 $formoptions['groups'] = []; 895 foreach ($groupcoursedata->groups as $groupid => $groupdata) { 896 $formoptions['groups'][$groupid] = $groupdata->name; 897 } 898 } 899 } 900 901 if (!empty($data['id'])) { 902 $eventid = clean_param($data['id'], PARAM_INT); 903 $legacyevent = calendar_event::load($eventid); 904 $legacyevent->count_repeats(); 905 $formoptions['event'] = $legacyevent; 906 $mform = new update_event_form(null, $formoptions, 'post', '', null, true, $data); 907 } else { 908 $legacyevent = null; 909 $mform = new create_event_form(null, $formoptions, 'post', '', null, true, $data); 910 } 911 912 if ($validateddata = $mform->get_data()) { 913 $formmapper = new create_update_form_mapper(); 914 $properties = $formmapper->from_data_to_event_properties($validateddata); 915 916 if (is_null($legacyevent)) { 917 $legacyevent = new \calendar_event($properties); 918 // Need to do this in order to initialise the description 919 // property which then triggers the update function below 920 // to set the appropriate default properties on the event. 921 $properties = $legacyevent->properties(true); 922 } 923 924 if (!calendar_edit_event_allowed($legacyevent, true)) { 925 print_error('nopermissiontoupdatecalendar'); 926 } 927 928 $legacyevent->update($properties); 929 $eventcontext = $legacyevent->context; 930 931 file_remove_editor_orphaned_files($validateddata->description); 932 933 // Take any files added to the description draft file area and 934 // convert them into the proper event description file area. Also 935 // parse the description text and replace the URLs to the draft files 936 // with the @@PLUGIN_FILE@@ placeholder to be persisted in the DB. 937 $description = file_save_draft_area_files( 938 $validateddata->description['itemid'], 939 $eventcontext->id, 940 'calendar', 941 'event_description', 942 $legacyevent->id, 943 create_event_form::build_editor_options($eventcontext), 944 $validateddata->description['text'] 945 ); 946 947 // If draft files were found then we need to save the new 948 // description value. 949 if ($description != $validateddata->description['text']) { 950 $properties->id = $legacyevent->id; 951 $properties->description = $description; 952 $legacyevent->update($properties); 953 } 954 955 $eventmapper = event_container::get_event_mapper(); 956 $event = $eventmapper->from_legacy_event_to_event($legacyevent); 957 $cache = new events_related_objects_cache([$event]); 958 $relatedobjects = [ 959 'context' => $cache->get_context($event), 960 'course' => $cache->get_course($event), 961 ]; 962 $exporter = new event_exporter($event, $relatedobjects); 963 $renderer = $PAGE->get_renderer('core_calendar'); 964 965 return [ 'event' => $exporter->export($renderer) ]; 966 } else { 967 return [ 'validationerror' => true ]; 968 } 969 } 970 971 /** 972 * Returns description of method result value. 973 * 974 * @return external_description. 975 */ 976 public static function submit_create_update_form_returns() { 977 $eventstructure = event_exporter::get_read_structure(); 978 $eventstructure->required = VALUE_OPTIONAL; 979 980 return new external_single_structure( 981 array( 982 'event' => $eventstructure, 983 'validationerror' => new external_value(PARAM_BOOL, 'Invalid form data', VALUE_DEFAULT, false), 984 ) 985 ); 986 } 987 988 /** 989 * Get data for the monthly calendar view. 990 * 991 * @param int $year The year to be shown 992 * @param int $month The month to be shown 993 * @param int $courseid The course to be included 994 * @param int $categoryid The category to be included 995 * @param bool $includenavigation Whether to include navigation 996 * @param bool $mini Whether to return the mini month view or not 997 * @param int $day The day we want to keep as the current day 998 * @return array 999 */ 1000 public static function get_calendar_monthly_view($year, $month, $courseid, $categoryid, $includenavigation, $mini, $day) { 1001 global $USER, $PAGE; 1002 1003 // Parameter validation. 1004 $params = self::validate_parameters(self::get_calendar_monthly_view_parameters(), [ 1005 'year' => $year, 1006 'month' => $month, 1007 'courseid' => $courseid, 1008 'categoryid' => $categoryid, 1009 'includenavigation' => $includenavigation, 1010 'mini' => $mini, 1011 'day' => $day, 1012 ]); 1013 1014 $context = \context_user::instance($USER->id); 1015 self::validate_context($context); 1016 $PAGE->set_url('/calendar/'); 1017 1018 $type = \core_calendar\type_factory::get_calendar_instance(); 1019 1020 $time = $type->convert_to_timestamp($params['year'], $params['month'], $params['day']); 1021 $calendar = \calendar_information::create($time, $params['courseid'], $params['categoryid']); 1022 self::validate_context($calendar->context); 1023 1024 $view = $params['mini'] ? 'mini' : 'month'; 1025 list($data, $template) = calendar_get_view($calendar, $view, $params['includenavigation']); 1026 1027 return $data; 1028 } 1029 1030 /** 1031 * Returns description of method parameters. 1032 * 1033 * @return external_function_parameters 1034 */ 1035 public static function get_calendar_monthly_view_parameters() { 1036 return new external_function_parameters( 1037 [ 1038 'year' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED), 1039 'month' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED), 1040 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), 1041 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), 1042 'includenavigation' => new external_value( 1043 PARAM_BOOL, 1044 'Whether to show course navigation', 1045 VALUE_DEFAULT, 1046 true, 1047 NULL_ALLOWED 1048 ), 1049 'mini' => new external_value( 1050 PARAM_BOOL, 1051 'Whether to return the mini month view or not', 1052 VALUE_DEFAULT, 1053 false, 1054 NULL_ALLOWED 1055 ), 1056 'day' => new external_value(PARAM_INT, 'Day to be viewed', VALUE_DEFAULT, 1), 1057 ] 1058 ); 1059 } 1060 1061 /** 1062 * Returns description of method result value. 1063 * 1064 * @return external_description 1065 */ 1066 public static function get_calendar_monthly_view_returns() { 1067 return \core_calendar\external\month_exporter::get_read_structure(); 1068 } 1069 1070 /** 1071 * Get data for the daily calendar view. 1072 * 1073 * @param int $year The year to be shown 1074 * @param int $month The month to be shown 1075 * @param int $day The day to be shown 1076 * @param int $courseid The course to be included 1077 * @return array 1078 */ 1079 public static function get_calendar_day_view($year, $month, $day, $courseid, $categoryid) { 1080 global $DB, $USER, $PAGE; 1081 1082 // Parameter validation. 1083 $params = self::validate_parameters(self::get_calendar_day_view_parameters(), [ 1084 'year' => $year, 1085 'month' => $month, 1086 'day' => $day, 1087 'courseid' => $courseid, 1088 'categoryid' => $categoryid, 1089 ]); 1090 1091 $context = \context_user::instance($USER->id); 1092 self::validate_context($context); 1093 1094 $type = \core_calendar\type_factory::get_calendar_instance(); 1095 1096 $time = $type->convert_to_timestamp($params['year'], $params['month'], $params['day']); 1097 $calendar = \calendar_information::create($time, $params['courseid'], $params['categoryid']); 1098 self::validate_context($calendar->context); 1099 1100 list($data, $template) = calendar_get_view($calendar, 'day'); 1101 1102 return $data; 1103 } 1104 1105 /** 1106 * Returns description of method parameters. 1107 * 1108 * @return external_function_parameters 1109 */ 1110 public static function get_calendar_day_view_parameters() { 1111 return new external_function_parameters( 1112 [ 1113 'year' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED), 1114 'month' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED), 1115 'day' => new external_value(PARAM_INT, 'Day to be viewed', VALUE_REQUIRED), 1116 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), 1117 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), 1118 ] 1119 ); 1120 } 1121 1122 /** 1123 * Returns description of method result value. 1124 * 1125 * @return external_description 1126 */ 1127 public static function get_calendar_day_view_returns() { 1128 return \core_calendar\external\calendar_day_exporter::get_read_structure(); 1129 } 1130 1131 1132 /** 1133 * Returns description of method parameters. 1134 * 1135 * @return external_function_parameters 1136 */ 1137 public static function update_event_start_day_parameters() { 1138 return new external_function_parameters( 1139 [ 1140 'eventid' => new external_value(PARAM_INT, 'Id of event to be updated', VALUE_REQUIRED), 1141 'daytimestamp' => new external_value(PARAM_INT, 'Timestamp for the new start day', VALUE_REQUIRED), 1142 ] 1143 ); 1144 } 1145 1146 /** 1147 * Change the start day for the given calendar event to the day that 1148 * corresponds with the provided timestamp. 1149 * 1150 * The timestamp only needs to be anytime within the desired day as only 1151 * the date data is extracted from it. 1152 * 1153 * The event's original time of day is maintained, only the date is shifted. 1154 * 1155 * @param int $eventid Id of event to be updated 1156 * @param int $daytimestamp Timestamp for the new start day 1157 * @return array 1158 */ 1159 public static function update_event_start_day($eventid, $daytimestamp) { 1160 global $USER, $PAGE; 1161 1162 // Parameter validation. 1163 $params = self::validate_parameters(self::update_event_start_day_parameters(), [ 1164 'eventid' => $eventid, 1165 'daytimestamp' => $daytimestamp, 1166 ]); 1167 1168 $vault = event_container::get_event_vault(); 1169 $mapper = event_container::get_event_mapper(); 1170 $event = $vault->get_event_by_id($eventid); 1171 1172 if (!$event) { 1173 throw new \moodle_exception('Unable to find event with id ' . $eventid); 1174 } 1175 1176 $legacyevent = $mapper->from_event_to_legacy_event($event); 1177 1178 if (!calendar_edit_event_allowed($legacyevent, true)) { 1179 print_error('nopermissiontoupdatecalendar'); 1180 } 1181 1182 self::validate_context($legacyevent->context); 1183 1184 $newdate = usergetdate($daytimestamp); 1185 $startdatestring = implode('-', [$newdate['year'], $newdate['mon'], $newdate['mday']]); 1186 $startdate = new DateTimeImmutable($startdatestring); 1187 $event = local_api::update_event_start_day($event, $startdate); 1188 $cache = new events_related_objects_cache([$event]); 1189 $relatedobjects = [ 1190 'context' => $cache->get_context($event), 1191 'course' => $cache->get_course($event), 1192 ]; 1193 $exporter = new event_exporter($event, $relatedobjects); 1194 $renderer = $PAGE->get_renderer('core_calendar'); 1195 1196 return array('event' => $exporter->export($renderer)); 1197 } 1198 1199 /** 1200 * Returns description of method result value. 1201 * 1202 * @return external_description 1203 */ 1204 public static function update_event_start_day_returns() { 1205 return new external_single_structure( 1206 array( 1207 'event' => event_exporter::get_read_structure() 1208 ) 1209 ); 1210 } 1211 1212 /** 1213 * Get data for the monthly calendar view. 1214 * 1215 * @param int $courseid The course to be included 1216 * @param int $categoryid The category to be included 1217 * @return array 1218 */ 1219 public static function get_calendar_upcoming_view($courseid, $categoryid) { 1220 global $DB, $USER, $PAGE; 1221 1222 // Parameter validation. 1223 $params = self::validate_parameters(self::get_calendar_upcoming_view_parameters(), [ 1224 'courseid' => $courseid, 1225 'categoryid' => $categoryid, 1226 ]); 1227 1228 $context = \context_user::instance($USER->id); 1229 self::validate_context($context); 1230 $PAGE->set_url('/calendar/'); 1231 1232 $calendar = \calendar_information::create(time(), $params['courseid'], $params['categoryid']); 1233 self::validate_context($calendar->context); 1234 1235 list($data, $template) = calendar_get_view($calendar, 'upcoming'); 1236 1237 return $data; 1238 } 1239 1240 /** 1241 * Returns description of method parameters. 1242 * 1243 * @return external_function_parameters 1244 */ 1245 public static function get_calendar_upcoming_view_parameters() { 1246 return new external_function_parameters( 1247 [ 1248 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), 1249 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), 1250 ] 1251 ); 1252 } 1253 1254 /** 1255 * Returns description of method result value. 1256 * 1257 * @return external_description 1258 */ 1259 public static function get_calendar_upcoming_view_returns() { 1260 return \core_calendar\external\calendar_upcoming_exporter::get_read_structure(); 1261 } 1262 1263 1264 /** 1265 * Returns description of method parameters. 1266 * 1267 * @return external_function_parameters. 1268 * @since Moodle 3.7 1269 */ 1270 public static function get_calendar_access_information_parameters() { 1271 return new external_function_parameters( 1272 [ 1273 'courseid' => new external_value(PARAM_INT, 'Course to check, empty for site calendar events.', VALUE_DEFAULT, 0), 1274 ] 1275 ); 1276 } 1277 1278 /** 1279 * Convenience function to retrieve some permissions information for the given course calendar. 1280 * 1281 * @param int $courseid Course to check, empty for site. 1282 * @return array The access information 1283 * @throws moodle_exception 1284 * @since Moodle 3.7 1285 */ 1286 public static function get_calendar_access_information($courseid = 0) { 1287 1288 $params = self::validate_parameters(self::get_calendar_access_information_parameters(), ['courseid' => $courseid]); 1289 1290 if (empty($params['courseid']) || $params['courseid'] == SITEID) { 1291 $context = \context_system::instance(); 1292 } else { 1293 $context = \context_course::instance($params['courseid']); 1294 } 1295 1296 self::validate_context($context); 1297 1298 return [ 1299 'canmanageentries' => has_capability('moodle/calendar:manageentries', $context), 1300 'canmanageownentries' => has_capability('moodle/calendar:manageownentries', $context), 1301 'canmanagegroupentries' => has_capability('moodle/calendar:managegroupentries', $context), 1302 'warnings' => [], 1303 ]; 1304 } 1305 1306 /** 1307 * Returns description of method result value. 1308 * 1309 * @return external_description. 1310 * @since Moodle 3.7 1311 */ 1312 public static function get_calendar_access_information_returns() { 1313 1314 return new external_single_structure( 1315 [ 1316 'canmanageentries' => new external_value(PARAM_BOOL, 'Whether the user can manage entries.'), 1317 'canmanageownentries' => new external_value(PARAM_BOOL, 'Whether the user can manage its own entries.'), 1318 'canmanagegroupentries' => new external_value(PARAM_BOOL, 'Whether the user can manage group entries.'), 1319 'warnings' => new external_warnings(), 1320 ] 1321 ); 1322 } 1323 1324 /** 1325 * Returns description of method parameters. 1326 * 1327 * @return external_function_parameters. 1328 * @since Moodle 3.7 1329 */ 1330 public static function get_allowed_event_types_parameters() { 1331 return new external_function_parameters( 1332 [ 1333 'courseid' => new external_value(PARAM_INT, 'Course to check, empty for site.', VALUE_DEFAULT, 0), 1334 ] 1335 ); 1336 } 1337 1338 /** 1339 * Get the type of events a user can create in the given course. 1340 * 1341 * @param int $courseid Course to check, empty for site. 1342 * @return array The types allowed 1343 * @throws moodle_exception 1344 * @since Moodle 3.7 1345 */ 1346 public static function get_allowed_event_types($courseid = 0) { 1347 1348 $params = self::validate_parameters(self::get_allowed_event_types_parameters(), ['courseid' => $courseid]); 1349 1350 if (empty($params['courseid']) || $params['courseid'] == SITEID) { 1351 $context = \context_system::instance(); 1352 } else { 1353 $context = \context_course::instance($params['courseid']); 1354 } 1355 1356 self::validate_context($context); 1357 1358 $allowedeventtypes = array_filter(calendar_get_allowed_event_types($params['courseid'])); 1359 1360 return [ 1361 'allowedeventtypes' => array_keys($allowedeventtypes), 1362 'warnings' => [], 1363 ]; 1364 } 1365 1366 /** 1367 * Returns description of method result value. 1368 * 1369 * @return external_description. 1370 * @since Moodle 3.7 1371 */ 1372 public static function get_allowed_event_types_returns() { 1373 1374 return new external_single_structure( 1375 [ 1376 'allowedeventtypes' => new external_multiple_structure( 1377 new external_value(PARAM_NOTAGS, 'Allowed event types to be created in the given course.') 1378 ), 1379 'warnings' => new external_warnings(), 1380 ] 1381 ); 1382 } 1383 1384 /** 1385 * Convert the specified dates into unix timestamps. 1386 * 1387 * @param array $datetimes Array of arrays containing date time details, each in the format: 1388 * ['year' => a, 'month' => b, 'day' => c, 1389 * 'hour' => d (optional), 'minute' => e (optional), 'key' => 'x' (optional)] 1390 * @return array Provided array of dates converted to unix timestamps 1391 * @throws moodle_exception If one or more of the dates provided does not convert to a valid timestamp. 1392 */ 1393 public static function get_timestamps($datetimes) { 1394 $params = self::validate_parameters(self::get_timestamps_parameters(), ['data' => $datetimes]); 1395 1396 $type = \core_calendar\type_factory::get_calendar_instance(); 1397 $timestamps = ['timestamps' => []]; 1398 1399 foreach ($params['data'] as $key => $datetime) { 1400 $hour = $datetime['hour'] ?? 0; 1401 $minute = $datetime['minute'] ?? 0; 1402 1403 try { 1404 $timestamp = $type->convert_to_timestamp( 1405 $datetime['year'], $datetime['month'], $datetime['day'], $hour, $minute); 1406 1407 $timestamps['timestamps'][] = [ 1408 'key' => $datetime['key'] ?? $key, 1409 'timestamp' => $timestamp, 1410 ]; 1411 1412 } catch (Exception $e) { 1413 throw new moodle_exception('One or more of the dates provided were invalid'); 1414 } 1415 } 1416 1417 return $timestamps; 1418 } 1419 1420 /** 1421 * Describes the parameters for get_timestamps. 1422 * 1423 * @return external_function_parameters 1424 */ 1425 public static function get_timestamps_parameters() { 1426 return new external_function_parameters ([ 1427 'data' => new external_multiple_structure( 1428 new external_single_structure( 1429 [ 1430 'key' => new external_value(PARAM_ALPHANUMEXT, 'key', VALUE_OPTIONAL), 1431 'year' => new external_value(PARAM_INT, 'year'), 1432 'month' => new external_value(PARAM_INT, 'month'), 1433 'day' => new external_value(PARAM_INT, 'day'), 1434 'hour' => new external_value(PARAM_INT, 'hour', VALUE_OPTIONAL), 1435 'minute' => new external_value(PARAM_INT, 'minute', VALUE_OPTIONAL), 1436 ] 1437 ) 1438 ) 1439 ]); 1440 } 1441 1442 /** 1443 * Describes the timestamps return format. 1444 * 1445 * @return external_single_structure 1446 */ 1447 public static function get_timestamps_returns() { 1448 return new external_single_structure( 1449 [ 1450 'timestamps' => new external_multiple_structure( 1451 new external_single_structure( 1452 [ 1453 'key' => new external_value(PARAM_ALPHANUMEXT, 'Timestamp key'), 1454 'timestamp' => new external_value(PARAM_INT, 'Unix timestamp'), 1455 ] 1456 ) 1457 ) 1458 ] 1459 ); 1460 } 1461} 1462