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