diff --git a/blocks/calendar_month/block_calendar_month.php b/blocks/calendar_month/block_calendar_month.php index a6172f93a3f..cc3d6f69f61 100644 --- a/blocks/calendar_month/block_calendar_month.php +++ b/blocks/calendar_month/block_calendar_month.php @@ -70,25 +70,25 @@ class block_calendar_month extends block_base { if ($issite) { // Being displayed at site level. This will cause the filter to fall back to auto-detecting // the list of courses it will be grabbing events from. - $filtercourse = \core_calendar\api::get_default_courses(); + $filtercourse = calendar_get_default_courses(); } else { // Forcibly filter events to include only those from the particular course we are in. $filtercourse = array($courseid => $this->page->course); } - list($courses, $group, $user) = \core_calendar\api::set_filters($filtercourse); + list($courses, $group, $user) = calendar_set_filters($filtercourse); if ($issite) { // For the front page. - $this->content->text .= \core_calendar\api::get_mini_calendar($courses, $group, $user, false, false, + $this->content->text .= calendar_get_mini($courses, $group, $user, false, false, 'frontpage', $courseid, $time); // No filters for now. } else { // For any other course. - $this->content->text .= \core_calendar\api::get_mini_calendar($courses, $group, $user, false, false, + $this->content->text .= calendar_get_mini($courses, $group, $user, false, false, 'course', $courseid, $time); $this->content->text .= '

'.get_string('eventskey', 'calendar').'

'; $this->content->text .= '
' . - \core_calendar\api::get_filter_controls($this->page->url) . '
'; + calendar_filter_controls($this->page->url) . ''; } return $this->content; diff --git a/blocks/calendar_upcoming/block_calendar_upcoming.php b/blocks/calendar_upcoming/block_calendar_upcoming.php index 3dab047ae38..858a0e42baf 100644 --- a/blocks/calendar_upcoming/block_calendar_upcoming.php +++ b/blocks/calendar_upcoming/block_calendar_upcoming.php @@ -65,14 +65,14 @@ class block_calendar_upcoming extends block_base { if ($courseshown == SITEID) { // Being displayed at site level. This will cause the filter to fall back to auto-detecting // the list of courses it will be grabbing events from. - $filtercourse = \core_calendar\api::get_default_courses(); + $filtercourse = calendar_get_default_courses(); } else { // Forcibly filter events to include only those from the particular course we are in. $filtercourse = array($courseshown => $this->page->course); } } - list($courses, $group, $user) = \core_calendar\api::set_filters($filtercourse); + list($courses, $group, $user) = calendar_set_filters($filtercourse); $defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD; if (isset($CFG->calendar_lookahead)) { @@ -85,7 +85,7 @@ class block_calendar_upcoming extends block_base { $defaultmaxevents = intval($CFG->calendar_maxevents); } $maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents); - $events = \core_calendar\api::get_upcoming($courses, $group, $user, $lookahead, $maxevents); + $events = calendar_get_upcoming($courses, $group, $user, $lookahead, $maxevents); if (!empty($this->instance)) { $link = 'view.php?view=day&course='.$courseshown.'&'; @@ -120,14 +120,14 @@ class block_calendar_upcoming extends block_base { if (!isset($events[$i]->time)) { continue; } - $events[$i] = \core_calendar\api::add_event_metadata($events[$i]); + $events[$i] = calendar_add_event_metadata($events[$i]); $content .= '
' . $events[$i]->icon . ''; if (!empty($events[$i]->referer)) { // That's an activity event, so let's provide the hyperlink. $content .= $events[$i]->referer; } else { if (!empty($linkhref)) { - $href = \core_calendar\api::get_link_href(new \moodle_url(CALENDAR_URL . $linkhref), 0, 0, 0, + $href = calendar_get_link_href(new \moodle_url(CALENDAR_URL . $linkhref), 0, 0, 0, $events[$i]->timestart); $href->set_anchor('event_' . $events[$i]->id); $content .= \html_writer::link($href, $events[$i]->name); diff --git a/calendar/classes/api.php b/calendar/classes/api.php index a053b9a523b..18d33f2d88d 100644 --- a/calendar/classes/api.php +++ b/calendar/classes/api.php @@ -24,8 +24,6 @@ namespace core_calendar; -use context_course; - defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/calendar/lib.php'); @@ -41,632 +39,6 @@ use core_calendar\local\api as local_api; */ class api { - /** - * Return the days of the week. - * - * @return array array of days - */ - public static function get_days() { - $calendartype = type_factory::get_calendar_instance(); - return $calendartype->get_weekdays(); - } - - /** - * Get the subscription from a given id. - * - * @param int $id id of the subscription - * @return \stdClass Subscription record from DB - * @throws \moodle_exception for an invalid id - */ - public static function get_subscription($id) { - global $DB; - - $cache = \cache::make('core', 'calendar_subscriptions'); - $subscription = $cache->get($id); - if (empty($subscription)) { - $subscription = $DB->get_record('event_subscriptions', array('id' => $id), '*', MUST_EXIST); - $cache->set($id, $subscription); - } - - return $subscription; - } - - /** - * Gets the first day of the week. - * - * @return int - */ - public static function get_starting_weekday() { - $calendartype = type_factory::get_calendar_instance(); - return $calendartype->get_starting_weekday(); - } - - /** - * Generates the HTML for a miniature calendar. - * - * @param array $courses list of course to list events from - * @param array $groups list of group - * @param array $users user's info - * @param int|bool $calmonth calendar month in numeric, default is set to false - * @param int|bool $calyear calendar month in numeric, default is set to false - * @param string|bool $placement the place/page the calendar is set to appear - passed on the the controls function - * @param int|bool $courseid id of the course the calendar is displayed on - passed on the the controls function - * @param int $time the unixtimestamp representing the date we want to view, this is used instead of $calmonth - * and $calyear to support multiple calendars - * @return string $content return html table for mini calendar - */ - public static function get_mini_calendar($courses, $groups, $users, $calmonth = false, $calyear = false, - $placement = false, $courseid = false, $time = 0) { - global $CFG, $OUTPUT, $PAGE; - - // Get the calendar type we are using. - $calendartype = type_factory::get_calendar_instance(); - - $display = new \stdClass; - - // Assume we are not displaying this month for now. - $display->thismonth = false; - - $content = ''; - - // Do this check for backwards compatibility. - // The core should be passing a timestamp rather than month and year. - // If a month and year are passed they will be in Gregorian. - if (!empty($calmonth) && !empty($calyear)) { - // Ensure it is a valid date, else we will just set it to the current timestamp. - if (checkdate($calmonth, 1, $calyear)) { - $time = make_timestamp($calyear, $calmonth, 1); - } else { - $time = time(); - } - $date = usergetdate($time); - if ($calmonth == $date['mon'] && $calyear == $date['year']) { - $display->thismonth = true; - } - // We can overwrite date now with the date used by the calendar type, - // if it is not Gregorian, otherwise there is no need as it is already in Gregorian. - if ($calendartype->get_name() != 'gregorian') { - $date = $calendartype->timestamp_to_date_array($time); - } - } else if (!empty($time)) { - // Get the specified date in the calendar type being used. - $date = $calendartype->timestamp_to_date_array($time); - $thisdate = $calendartype->timestamp_to_date_array(time()); - if ($date['month'] == $thisdate['month'] && $date['year'] == $thisdate['year']) { - $display->thismonth = true; - // If we are the current month we want to set the date to the current date, not the start of the month. - $date = $thisdate; - } - } else { - // Get the current date in the calendar type being used. - $time = time(); - $date = $calendartype->timestamp_to_date_array($time); - $display->thismonth = true; - } - - list($d, $m, $y) = array($date['mday'], $date['mon'], $date['year']); // This is what we want to display. - - // Get Gregorian date for the start of the month. - $gregoriandate = $calendartype->convert_to_gregorian($date['year'], $date['mon'], 1); - - // Store the gregorian date values to be used later. - list($gy, $gm, $gd, $gh, $gmin) = array($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'], - $gregoriandate['hour'], $gregoriandate['minute']); - - // Get the max number of days in this month for this calendar type. - $display->maxdays = self::get_days_in_month($m, $y); - // Get the starting week day for this month. - $startwday = dayofweek(1, $m, $y); - // Get the days in a week. - $daynames = self::get_days(); - // Store the number of days in a week. - $numberofdaysinweek = $calendartype->get_num_weekdays(); - - // Set the min and max weekday. - $display->minwday = self::get_starting_weekday(); - $display->maxwday = $display->minwday + ($numberofdaysinweek - 1); - - // These are used for DB queries, so we want unixtime, so we need to use Gregorian dates. - $display->tstart = make_timestamp($gy, $gm, $gd, $gh, $gmin, 0); - $display->tend = $display->tstart + ($display->maxdays * DAYSECS) - 1; - - // Align the starting weekday to fall in our display range. - // This is simple, not foolproof. - if ($startwday < $display->minwday) { - $startwday += $numberofdaysinweek; - } - - // Get the events matching our criteria. Don't forget to offset the timestamps for the user's TZ. - $events = self::get_events($display->tstart, $display->tend, $users, $groups, $courses); - - // Set event course class for course events. - if (!empty($events)) { - foreach ($events as $eventid => $event) { - if (!empty($event->modulename)) { - $cm = get_coursemodule_from_instance($event->modulename, $event->instance); - if (!\core_availability\info_module::is_user_visible($cm, 0, false)) { - unset($events[$eventid]); - } - } - } - } - - // This is either a genius idea or an idiot idea: in order to not complicate things, we use this rule: if, after - // possibly removing SITEID from $courses, there is only one course left, then clicking on a day in the month - // will also set the $SESSION->cal_courses_shown variable to that one course. Otherwise, we 'd need to add extra - // arguments to this function. - $hrefparams = array(); - if (!empty($courses)) { - $courses = array_diff($courses, array(SITEID)); - if (count($courses) == 1) { - $hrefparams['course'] = reset($courses); - } - } - - // We want to have easy access by day, since the display is on a per-day basis. - self::get_events_by_day($events, $m, $y, $eventsbyday, $durationbyday, $typesbyday, $courses); - - // Accessibility: added summary and elements. - $summary = get_string('calendarheading', 'calendar', userdate($display->tstart, get_string('strftimemonthyear'))); - // Begin table. - $content .= ''; - if (($placement !== false) && ($courseid !== false)) { - $content .= ''; - } - $content .= ''; // Header row: day names. - - // Print out the names of the weekdays. - for ($i = $display->minwday; $i <= $display->maxwday; $i++) { - $pos = $i % $numberofdaysinweek; - $content .= '\n"; - } - - $content .= ''; // End of day names; prepare for day numbers. - - // For the table display. $week is the row; $dayweek is the column. - $dayweek = $startwday; - - // Padding (the first week may have blank days in the beginning). - for ($i = $display->minwday; $i < $startwday; ++$i) { - $content .= '' ."\n"; - } - - $weekend = CALENDAR_DEFAULT_WEEKEND; - if (isset($CFG->calendar_weekend)) { - $weekend = intval($CFG->calendar_weekend); - } - - // Now display all the calendar. - $daytime = strtotime('-1 day', $display->tstart); - for ($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) { - $cellattributes = array(); - $daytime = strtotime('+1 day', $daytime); - if ($dayweek > $display->maxwday) { - // We need to change week (table row). - $content .= ''; - $dayweek = $display->minwday; - } - - // Reset vars. - if ($weekend & (1 << ($dayweek % $numberofdaysinweek))) { - // Weekend. This is true no matter what the exact range is. - $class = 'weekend day'; - } else { - // Normal working day. - $class = 'day'; - } - - $eventids = array(); - if (!empty($eventsbyday[$day])) { - $eventids = $eventsbyday[$day]; - } - - if (!empty($durationbyday[$day])) { - $eventids = array_unique(array_merge($eventids, $durationbyday[$day])); - } - - $finishclass = false; - - if (!empty($eventids)) { - // There is at least one event on this day. - $class .= ' hasevent'; - $hrefparams['view'] = 'day'; - $dayhref = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $hrefparams), 0, 0, 0, $daytime); - - $popupcontent = ''; - foreach ($eventids as $eventid) { - if (!isset($events[$eventid])) { - continue; - } - $event = new \calendar_event($events[$eventid]); - $popupalt = ''; - $component = 'moodle'; - if (!empty($event->modulename)) { - $popupicon = 'icon'; - $popupalt = $event->modulename; - $component = $event->modulename; - } else if ($event->courseid == SITEID) { // Site event. - $popupicon = 'i/siteevent'; - } else if ($event->courseid != 0 && $event->courseid != SITEID - && $event->groupid == 0) { // Course event. - $popupicon = 'i/courseevent'; - } else if ($event->groupid) { // Group event. - $popupicon = 'i/groupevent'; - } else { // Must be a user event. - $popupicon = 'i/userevent'; - } - - if ($event->timeduration) { - $startdate = $calendartype->timestamp_to_date_array($event->timestart); - $enddate = $calendartype->timestamp_to_date_array($event->timestart + $event->timeduration - 1); - if ($enddate['mon'] == $m && $enddate['year'] == $y && $enddate['mday'] == $day) { - $finishclass = true; - } - } - - $dayhref->set_anchor('event_' . $event->id); - - $popupcontent .= \html_writer::start_tag('div'); - $popupcontent .= $OUTPUT->pix_icon($popupicon, $popupalt, $component); - // Show ical source if needed. - if (!empty($event->subscription) && $CFG->calendar_showicalsource) { - $a = new \stdClass(); - $a->name = format_string($event->name, true); - $a->source = $event->subscription->name; - $name = get_string('namewithsource', 'calendar', $a); - } else { - if ($finishclass) { - $samedate = $startdate['mon'] == $enddate['mon'] && - $startdate['year'] == $enddate['year'] && - $startdate['mday'] == $enddate['mday']; - - if ($samedate) { - $name = format_string($event->name, true); - } else { - $name = format_string($event->name, true) . ' (' . get_string('eventendtime', 'calendar') . ')'; - } - } else { - $name = format_string($event->name, true); - } - } - $popupcontent .= \html_writer::link($dayhref, $name); - $popupcontent .= \html_writer::end_tag('div'); - } - - if ($display->thismonth && $day == $d) { - $popupdata = self::get_popup(true, $daytime, $popupcontent); - } else { - $popupdata = self::get_popup(false, $daytime, $popupcontent); - } - - // Class and cell content. - if (isset($typesbyday[$day]['startglobal'])) { - $class .= ' calendar_event_global'; - } else if (isset($typesbyday[$day]['startcourse'])) { - $class .= ' calendar_event_course'; - } else if (isset($typesbyday[$day]['startgroup'])) { - $class .= ' calendar_event_group'; - } else if (isset($typesbyday[$day]['startuser'])) { - $class .= ' calendar_event_user'; - } - if ($finishclass) { - $class .= ' duration_finish'; - } - $data = array( - 'url' => $dayhref, - 'day' => $day, - 'content' => $popupdata['data-core_calendar-popupcontent'], - 'title' => $popupdata['data-core_calendar-title'] - ); - $cell = $OUTPUT->render_from_template('core_calendar/minicalendar_day_link', $data); - } else { - $cell = $day; - } - - $durationclass = false; - if (isset($typesbyday[$day]['durationglobal'])) { - $durationclass = ' duration_global'; - } else if (isset($typesbyday[$day]['durationcourse'])) { - $durationclass = ' duration_course'; - } else if (isset($typesbyday[$day]['durationgroup'])) { - $durationclass = ' duration_group'; - } else if (isset($typesbyday[$day]['durationuser'])) { - $durationclass = ' duration_user'; - } - if ($durationclass) { - $class .= ' duration ' . $durationclass; - } - - // If event has a class set then add it to the table day '; - } - $content .= ''; // Last row ends. - - $content .= '
' . self::get_top_controls($placement, - array('id' => $courseid, 'time' => $time)) . '
' . - $daynames[$pos]['shortname'] . "
 
tag. - // Note: only one colour for minicalendar. - if (isset($eventsbyday[$day])) { - foreach ($eventsbyday[$day] as $eventid) { - if (!isset($events[$eventid])) { - continue; - } - $event = $events[$eventid]; - if (!empty($event->class)) { - $class .= ' ' . $event->class; - } - break; - } - } - - if ($display->thismonth && $day == $d) { - // The current cell is for today - add appropriate classes and additional information for styling. - $class .= ' today'; - $today = get_string('today', 'calendar') . ' ' . userdate(time(), get_string('strftimedayshort')); - - if (!isset($eventsbyday[$day]) && !isset($durationbyday[$day])) { - $class .= ' eventnone'; - $popupdata = self::get_popup(true, false); - $data = array( - 'url' => '#', - 'day' => $day, - 'content' => $popupdata['data-core_calendar-popupcontent'], - 'title' => $popupdata['data-core_calendar-title'] - ); - $cell = $OUTPUT->render_from_template('core_calendar/minicalendar_day_link', $data); - } - $cell = get_accesshide($today . ' ') . $cell; - } - - // Just display it. - $cellattributes['class'] = $class; - $content .= \html_writer::tag('td', $cell, $cellattributes); - } - - // Padding (the last week may have blank days at the end). - for ($i = $dayweek; $i <= $display->maxwday; ++$i) { - $content .= ' 
'; // Tabular display of days ends. - return $content; - } - - /** - * Gets the calendar popup. - * - * @param bool $today false except when called on the current day. - * @param mixed $timestart $events[$eventid]->timestart, OR false if there are no events. - * @param string $popupcontent content for the popup window/layout. - * @return string eventid for the calendar_tooltip popup window/layout. - */ - public static function get_popup($today = false, $timestart, $popupcontent = '') { - $popupcaption = ''; - if ($today) { - $popupcaption = get_string('today', 'calendar') . ' '; - } - - if (false === $timestart) { - $popupcaption .= userdate(time(), get_string('strftimedayshort')); - $popupcontent = get_string('eventnone', 'calendar'); - - } else { - $popupcaption .= get_string('eventsfor', 'calendar', userdate($timestart, get_string('strftimedayshort'))); - } - - return array( - 'data-core_calendar-title' => $popupcaption, - 'data-core_calendar-popupcontent' => $popupcontent, - ); - } - - /** - * Gets the calendar upcoming events. - * - * @param array $courses array of courses - * @param array|int|bool $groups array of groups, group id or boolean for all/no group events - * @param array|int|bool $users array of users, user id or boolean for all/no user events - * @param int $daysinfuture number of days in the future we 'll look - * @param int $maxevents maximum number of events - * @param int $fromtime start time - * @return array $output array of upcoming events - */ - public static function get_upcoming($courses, $groups, $users, $daysinfuture, $maxevents, $fromtime = 0) { - global $COURSE; - - $display = new \stdClass; - $display->range = $daysinfuture; // How many days in the future we 'll look. - $display->maxevents = $maxevents; - - $output = array(); - - $processed = 0; - $now = time(); // We 'll need this later. - $usermidnighttoday = usergetmidnight($now); - - if ($fromtime) { - $display->tstart = $fromtime; - } else { - $display->tstart = $usermidnighttoday; - } - - // This works correctly with respect to the user's DST, but it is accurate - // only because $fromtime is always the exact midnight of some day! - $display->tend = usergetmidnight($display->tstart + DAYSECS * $display->range + 3 * HOURSECS) - 1; - - // Get the events matching our criteria. - $events = self::get_events($display->tstart, $display->tend, $users, $groups, $courses); - - // This is either a genius idea or an idiot idea: in order to not complicate things, we use this rule: if, after - // possibly removing SITEID from $courses, there is only one course left, then clicking on a day in the month - // will also set the $SESSION->cal_courses_shown variable to that one course. Otherwise, we 'd need to add extra - // arguments to this function. - $hrefparams = array(); - if (!empty($courses)) { - $courses = array_diff($courses, array(SITEID)); - if (count($courses) == 1) { - $hrefparams['course'] = reset($courses); - } - } - - if ($events !== false) { - $modinfo = get_fast_modinfo($COURSE); - foreach ($events as $event) { - if (!empty($event->modulename)) { - if ($event->courseid == $COURSE->id) { - if (isset($modinfo->instances[$event->modulename][$event->instance])) { - $cm = $modinfo->instances[$event->modulename][$event->instance]; - if (!$cm->uservisible) { - continue; - } - } - } else { - if (!$cm = get_coursemodule_from_instance($event->modulename, $event->instance)) { - continue; - } - if (!\core_availability\info_module::is_user_visible($cm, 0, false)) { - continue; - } - } - } - - if ($processed >= $display->maxevents) { - break; - } - - $event->time = self::get_format_event_time($event, $now, $hrefparams); - $output[] = $event; - $processed++; - } - } - - return $output; - } - - /** - * Get a HTML link to a course. - * - * @param int $courseid the course id - * @return string a link to the course (as HTML); empty if the course id is invalid - */ - public static function get_courselink($courseid) { - if (!$courseid) { - return ''; - } - - self::get_course_cached($coursecache, $courseid); - $context = \context_course::instance($courseid); - $fullname = format_string($coursecache[$courseid]->fullname, true, array('context' => $context)); - $url = new \moodle_url('/course/view.php', array('id' => $courseid)); - $link = \html_writer::link($url, $fullname); - - return $link; - } - - /** - * Get current module cache. - * - * @param array $modulecache in memory module cache - * @param string $modulename name of the module - * @param int $instance module instance number - * @return \stdClass|bool $module information - */ - public static function get_module_cached(&$modulecache, $modulename, $instance) { - if (!isset($modulecache[$modulename . '_' . $instance])) { - $modulecache[$modulename . '_' . $instance] = get_coursemodule_from_instance($modulename, $instance); - } - - return $modulecache[$modulename . '_' . $instance]; - } - - /** - * Get current course cache. - * - * @param array $coursecache list of course cache - * @param int $courseid id of the course - * @return \stdClass $coursecache[$courseid] return the specific course cache - */ - public static function get_course_cached(&$coursecache, $courseid) { - if (!isset($coursecache[$courseid])) { - $coursecache[$courseid] = get_course($courseid); - } - return $coursecache[$courseid]; - } - - /** - * Get group from groupid for calendar display. - * - * @param int $groupid - * @return \stdClass group object with fields 'id', 'name' and 'courseid' - */ - public static function get_group_cached($groupid) { - static $groupscache = array(); - if (!isset($groupscache[$groupid])) { - $groupscache[$groupid] = groups_get_group($groupid, 'id,name,courseid'); - } - return $groupscache[$groupid]; - } - - /** - * Add calendar event metadata. - * - * @param \stdClass $event event info - * @return \stdClass $event metadata - */ - public static function add_event_metadata($event) { - global $CFG, $OUTPUT; - - // Support multilang in event->name. - $event->name = format_string($event->name, true); - - if (!empty($event->modulename)) { // Activity event. - // The module name is set. I will assume that it has to be displayed, and - // also that it is an automatically-generated event. And of course that the - // fields for get_coursemodule_from_instance are set correctly. - $module = self::get_module_cached($coursecache, $event->modulename, $event->instance); - - if ($module === false) { - return; - } - - $modulename = get_string('modulename', $event->modulename); - if (get_string_manager()->string_exists($event->eventtype, $event->modulename)) { - // Will be used as alt text if the event icon. - $eventtype = get_string($event->eventtype, $event->modulename); - } else { - $eventtype = ''; - } - $icon = $OUTPUT->image_url('icon', $event->modulename) . ''; - - $event->icon = '' . $eventtype . ''; - $event->referer = '' . $event->name . ''; - $event->courselink = self::get_courselink($module->course); - $event->cmid = $module->id; - } else if ($event->courseid == SITEID) { // Site event. - $event->icon = '' .
-                get_string('globalevent', 'calendar') . ''; - $event->cssclass = 'calendar_event_global'; - } else if ($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { // Course event. - $event->icon = '' .
-                get_string('courseevent', 'calendar') . ''; - $event->courselink = self::get_courselink($event->courseid); - $event->cssclass = 'calendar_event_course'; - } else if ($event->groupid) { // Group event. - if ($group = self::get_group_cached($event->groupid)) { - $groupname = format_string($group->name, true, \context_course::instance($group->courseid)); - } else { - $groupname = ''; - } - $event->icon = \html_writer::empty_tag('image', array('src' => $OUTPUT->image_url('i/groupevent'), - 'alt' => get_string('groupevent', 'calendar'), 'title' => $groupname, 'class' => 'icon')); - $event->courselink = self::get_courselink($event->courseid) . ', ' . $groupname; - $event->cssclass = 'calendar_event_group'; - } else if ($event->userid) { // User event. - $event->icon = '' .
-                get_string('userevent', 'calendar') . ''; - $event->cssclass = 'calendar_event_user'; - } - - return $event; - } - /** * Get calendar events * @@ -715,1464 +87,6 @@ class api { }, []); } - /** - * Get calendar events by id. - * - * @param array $eventids list of event ids - * @return array Array of event entries, empty array if nothing found - */ - public static function get_events_by_id($eventids) { - global $DB; - - if (!is_array($eventids) || empty($eventids)) { - return array(); - } - - list($wheresql, $params) = $DB->get_in_or_equal($eventids); - $wheresql = "id $wheresql"; - - return $DB->get_records_select('event', $wheresql, $params); - } - - /** - * Get control options for calendar. - * - * @param string $type of calendar - * @param array $data calendar information - * @return string $content return available control for the calender in html - */ - public static function get_top_controls($type, $data) { - global $PAGE, $OUTPUT; - - // Get the calendar type we are using. - $calendartype = type_factory::get_calendar_instance(); - - $content = ''; - - // Ensure course id passed if relevant. - $courseid = ''; - if (!empty($data['id'])) { - $courseid = '&course=' . $data['id']; - } - - // If we are passing a month and year then we need to convert this to a timestamp to - // support multiple calendars. No where in core should these be passed, this logic - // here is for third party plugins that may use this function. - if (!empty($data['m']) && !empty($date['y'])) { - if (!isset($data['d'])) { - $data['d'] = 1; - } - if (!checkdate($data['m'], $data['d'], $data['y'])) { - $time = time(); - } else { - $time = make_timestamp($data['y'], $data['m'], $data['d']); - } - } else if (!empty($data['time'])) { - $time = $data['time']; - } else { - $time = time(); - } - - // Get the date for the calendar type. - $date = $calendartype->timestamp_to_date_array($time); - - $urlbase = $PAGE->url; - - // We need to get the previous and next months in certain cases. - if ($type == 'frontpage' || $type == 'course' || $type == 'month') { - $prevmonth = self::get_prev_month($date['mon'], $date['year']); - $prevmonthtime = $calendartype->convert_to_gregorian($prevmonth[1], $prevmonth[0], 1); - $prevmonthtime = make_timestamp($prevmonthtime['year'], $prevmonthtime['month'], $prevmonthtime['day'], - $prevmonthtime['hour'], $prevmonthtime['minute']); - - $nextmonth = self::get_next_month($date['mon'], $date['year']); - $nextmonthtime = $calendartype->convert_to_gregorian($nextmonth[1], $nextmonth[0], 1); - $nextmonthtime = make_timestamp($nextmonthtime['year'], $nextmonthtime['month'], $nextmonthtime['day'], - $nextmonthtime['hour'], $nextmonthtime['minute']); - } - - switch ($type) { - case 'frontpage': - $prevlink = self::get_link_previous(get_string('monthprev', 'access'), $urlbase, false, false, false, - true, $prevmonthtime); - $nextlink = self::get_link_next(get_string('monthnext', 'access'), $urlbase, false, false, false, true, - $nextmonthtime); - $calendarlink = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', array('view' => 'month')), - false, false, false, $time); - - if (!empty($data['id'])) { - $calendarlink->param('course', $data['id']); - } - - $right = $nextlink; - - $content .= \html_writer::start_tag('div', array('class' => 'calendar-controls')); - $content .= $prevlink . ' | '; - $content .= \html_writer::tag('span', \html_writer::link($calendarlink, - userdate($time, get_string('strftimemonthyear')), array('title' => get_string('monththis', 'calendar')) - ), array('class' => 'current')); - $content .= ' | ' . $right; - $content .= "\n"; - $content .= \html_writer::end_tag('div'); - - break; - case 'course': - $prevlink = self::get_link_previous(get_string('monthprev', 'access'), $urlbase, false, false, false, - true, $prevmonthtime); - $nextlink = self::get_link_next(get_string('monthnext', 'access'), $urlbase, false, false, false, - true, $nextmonthtime); - $calendarlink = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', array('view' => 'month')), - false, false, false, $time); - - if (!empty($data['id'])) { - $calendarlink->param('course', $data['id']); - } - - $content .= \html_writer::start_tag('div', array('class' => 'calendar-controls')); - $content .= $prevlink . ' | '; - $content .= \html_writer::tag('span', \html_writer::link($calendarlink, - userdate($time, get_string('strftimemonthyear')), array('title' => get_string('monththis', 'calendar')) - ), array('class' => 'current')); - $content .= ' | ' . $nextlink; - $content .= ""; - $content .= \html_writer::end_tag('div'); - break; - case 'upcoming': - $calendarlink = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', array('view' => 'upcoming')), - false, false, false, $time); - if (!empty($data['id'])) { - $calendarlink->param('course', $data['id']); - } - $calendarlink = \html_writer::link($calendarlink, userdate($time, get_string('strftimemonthyear'))); - $content .= \html_writer::tag('div', $calendarlink, array('class' => 'centered')); - break; - case 'display': - $calendarlink = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', array('view' => 'month')), - false, false, false, $time); - if (!empty($data['id'])) { - $calendarlink->param('course', $data['id']); - } - $calendarlink = \html_writer::link($calendarlink, userdate($time, get_string('strftimemonthyear'))); - $content .= \html_writer::tag('h3', $calendarlink); - break; - case 'month': - $prevlink = self::get_link_previous(userdate($prevmonthtime, get_string('strftimemonthyear')), - 'view.php?view=month' . $courseid . '&', false, false, false, false, $prevmonthtime); - $nextlink = self::get_link_next(userdate($nextmonthtime, get_string('strftimemonthyear')), - 'view.php?view=month' . $courseid . '&', false, false, false, false, $nextmonthtime); - - $content .= \html_writer::start_tag('div', array('class' => 'calendar-controls')); - $content .= $prevlink . ' | '; - $content .= $OUTPUT->heading(userdate($time, get_string('strftimemonthyear')), 2, 'current'); - $content .= ' | ' . $nextlink; - $content .= ''; - $content .= \html_writer::end_tag('div')."\n"; - break; - case 'day': - $days = self::get_days(); - - $prevtimestamp = strtotime('-1 day', $time); - $nexttimestamp = strtotime('+1 day', $time); - - $prevdate = $calendartype->timestamp_to_date_array($prevtimestamp); - $nextdate = $calendartype->timestamp_to_date_array($nexttimestamp); - - $prevname = $days[$prevdate['wday']]['fullname']; - $nextname = $days[$nextdate['wday']]['fullname']; - $prevlink = self::get_link_previous($prevname, 'view.php?view=day' . $courseid . '&', false, false, - false, false, $prevtimestamp); - $nextlink = self::get_link_next($nextname, 'view.php?view=day' . $courseid . '&', false, false, false, - false, $nexttimestamp); - - $content .= \html_writer::start_tag('div', array('class' => 'calendar-controls')); - $content .= $prevlink; - $content .= ' | ' .userdate($time, - get_string('strftimedaydate')) . ''; - $content .= ' | ' . $nextlink; - $content .= ""; - $content .= \html_writer::end_tag('div') . "\n"; - - break; - } - - return $content; - } - - /** - * Formats a filter control element. - * - * @param \moodle_url $url of the filter - * @param int $type constant defining the type filter - * @return string html content of the element - */ - public static function get_filter_controls_element(\moodle_url $url, $type) { - global $OUTPUT; - - switch ($type) { - case CALENDAR_EVENT_GLOBAL: - $typeforhumans = 'global'; - $class = 'calendar_event_global'; - break; - case CALENDAR_EVENT_COURSE: - $typeforhumans = 'course'; - $class = 'calendar_event_course'; - break; - case CALENDAR_EVENT_GROUP: - $typeforhumans = 'groups'; - $class = 'calendar_event_group'; - break; - case CALENDAR_EVENT_USER: - $typeforhumans = 'user'; - $class = 'calendar_event_user'; - break; - } - - if (self::show_event_type($type)) { - $icon = $OUTPUT->pix_icon('t/hide', get_string('hide')); - $str = get_string('hide' . $typeforhumans . 'events', 'calendar'); - } else { - $icon = $OUTPUT->pix_icon('t/show', get_string('show')); - $str = get_string('show' . $typeforhumans . 'events', 'calendar'); - } - $content = \html_writer::start_tag('li', array('class' => 'calendar_event')); - $content .= \html_writer::start_tag('a', array('href' => $url, 'rel' => 'nofollow')); - $content .= \html_writer::tag('span', $icon, array('class' => $class)); - $content .= \html_writer::tag('span', $str, array('class' => 'eventname')); - $content .= \html_writer::end_tag('a'); - $content .= \html_writer::end_tag('li'); - - return $content; - } - - /** - * Get the controls filter for calendar. - * - * Filter is used to hide calendar info from the display page - * - * @param \moodle_url $returnurl return-url for filter controls - * @return string $content return filter controls in html - */ - public static function get_filter_controls(\moodle_url $returnurl) { - $groupevents = true; - - $seturl = new \moodle_url('/calendar/set.php', array('return' => base64_encode($returnurl->out_as_local_url(false)), - 'sesskey' => sesskey())); - $content = \html_writer::start_tag('ul'); - - $seturl->param('var', 'showglobal'); - $content .= self::get_filter_controls_element($seturl, CALENDAR_EVENT_GLOBAL); - - $seturl->param('var', 'showcourses'); - $content .= self::get_filter_controls_element($seturl, CALENDAR_EVENT_COURSE); - - if (isloggedin() && !isguestuser()) { - if ($groupevents) { - // This course MIGHT have group events defined, so show the filter. - $seturl->param('var', 'showgroups'); - $content .= self::get_filter_controls_element($seturl, CALENDAR_EVENT_GROUP); - } - $seturl->param('var', 'showuser'); - $content .= self::get_filter_controls_element($seturl, CALENDAR_EVENT_USER); - } - $content .= \html_writer::end_tag('ul'); - - return $content; - } - - /** - * Return the representation day - * - * @param int $tstamp Timestamp in GMT - * @param int|bool $now current Unix timestamp - * @param bool $usecommonwords - * @return string the formatted date/time - */ - public static function get_day_representation($tstamp, $now = false, $usecommonwords = true) { - - static $shortformat; - if (empty($shortformat)) { - $shortformat = get_string('strftimedayshort'); - } - - if ($now === false) { - $now = time(); - } - - // To have it in one place, if a change is needed. - $formal = userdate($tstamp, $shortformat); - - $datestamp = usergetdate($tstamp); - $datenow = usergetdate($now); - - if ($usecommonwords == false) { - // We don't want words, just a date. - return $formal; - } else if ($datestamp['year'] == $datenow['year'] && $datestamp['yday'] == $datenow['yday']) { - return get_string('today', 'calendar'); - } else if (($datestamp['year'] == $datenow['year'] && $datestamp['yday'] == $datenow['yday'] - 1 ) || - ($datestamp['year'] == $datenow['year'] - 1 && $datestamp['mday'] == 31 && $datestamp['mon'] == 12 - && $datenow['yday'] == 1)) { - return get_string('yesterday', 'calendar'); - } else if (($datestamp['year'] == $datenow['year'] && $datestamp['yday'] == $datenow['yday'] + 1 ) || - ($datestamp['year'] == $datenow['year'] + 1 && $datenow['mday'] == 31 && $datenow['mon'] == 12 - && $datestamp['yday'] == 1)) { - return get_string('tomorrow', 'calendar'); - } else { - return $formal; - } - } - - /** - * return the formatted representation time - * - * @param int $time the timestamp in UTC, as obtained from the database - * @return string the formatted date/time - */ - public static function get_time_representation($time) { - static $langtimeformat = null; - - if ($langtimeformat === null) { - $langtimeformat = get_string('strftimetime'); - } - - $timeformat = get_user_preferences('calendar_timeformat'); - if (empty($timeformat)) { - $timeformat = get_config(null, 'calendar_site_timeformat'); - } - - return userdate($time, empty($timeformat) ? $langtimeformat : $timeformat); - } - - /** - * Adds day, month, year arguments to a URL and returns a moodle_url object. - * - * @param string|\moodle_url $linkbase - * @param int $d The number of the day. - * @param int $m The number of the month. - * @param int $y The number of the year. - * @param int $time the unixtime, used for multiple calendar support. The values $d, - * $m and $y are kept for backwards compatibility. - * @return \moodle_url|null $linkbase - */ - public static function get_link_href($linkbase, $d, $m, $y, $time = 0) { - if (empty($linkbase)) { - return null; - } - - if (!($linkbase instanceof \moodle_url)) { - $linkbase = new \moodle_url($linkbase); - } - - // If a day, month and year were passed then convert it to a timestamp. If these were passed - // then we can assume the day, month and year are passed as Gregorian, as no where in core - // should we be passing these values rather than the time. - if (!empty($d) && !empty($m) && !empty($y)) { - if (checkdate($m, $d, $y)) { - $time = make_timestamp($y, $m, $d); - } else { - $time = time(); - } - } else if (empty($time)) { - $time = time(); - } - - $linkbase->param('time', $time); - - return $linkbase; - } - - /** - * Build and return a previous month HTML link, with an arrow. - * - * @param string $text The text label. - * @param string|\moodle_url $linkbase The URL stub. - * @param int $d The number of the date. - * @param int $m The number of the month. - * @param int $y year The number of the year. - * @param bool $accesshide Default visible, or hide from all except screenreaders. - * @param int $time the unixtime, used for multiple calendar support. The values $d, - * $m and $y are kept for backwards compatibility. - * @return string HTML string. - */ - public static function get_link_previous($text, $linkbase, $d, $m, $y, $accesshide = false, $time = 0) { - $href = self::get_link_href(new \moodle_url($linkbase), $d, $m, $y, $time); - - if (empty($href)) { - return $text; - } - - return link_arrow_left($text, (string)$href, $accesshide, 'previous'); - } - - /** - * Build and return a next month HTML link, with an arrow. - * - * @param string $text The text label. - * @param string|\moodle_url $linkbase The URL stub. - * @param int $d the number of the Day - * @param int $m The number of the month. - * @param int $y The number of the year. - * @param bool $accesshide Default visible, or hide from all except screenreaders. - * @param int $time the unixtime, used for multiple calendar support. The values $d, - * $m and $y are kept for backwards compatibility. - * @return string HTML string. - */ - public static function get_link_next($text, $linkbase, $d, $m, $y, $accesshide = false, $time = 0) { - $href = self::get_link_href(new \moodle_url($linkbase), $d, $m, $y, $time); - - if (empty($href)) { - return $text; - } - - return link_arrow_right($text, (string)$href, $accesshide, 'next'); - } - - /** - * Return the number of days in month - * - * @param int $month the number of the month. - * @param int $year the number of the year - * @return int - */ - public static function get_days_in_month($month, $year) { - $calendartype = type_factory::get_calendar_instance(); - return $calendartype->get_num_days_in_month($year, $month); - } - - /** - * Get the next following month - * - * @param int $month the number of the month. - * @param int $year the number of the year. - * @return array the following month - */ - public static function get_next_month($month, $year) { - $calendartype = type_factory::get_calendar_instance(); - return $calendartype->get_next_month($year, $month); - } - - /** - * Get the previous month. - * - * @param int $month the number of the month. - * @param int $year the number of the year. - * @return array previous month - */ - public static function get_prev_month($month, $year) { - $calendartype = type_factory::get_calendar_instance(); - return $calendartype->get_prev_month($year, $month); - } - - /** - * Get per-day basis events. - * - * @param array $events list of events - * @param int $month the number of the month - * @param int $year the number of the year - * @param array $eventsbyday event on specific day - * @param array $durationbyday duration of the event in days - * @param array $typesbyday event type (eg: global, course, user, or group) - * @param array $courses list of courses - * @return void - */ - public static function get_events_by_day($events, $month, $year, &$eventsbyday, &$durationbyday, &$typesbyday, &$courses) { - $calendartype = type_factory::get_calendar_instance(); - - $eventsbyday = array(); - $typesbyday = array(); - $durationbyday = array(); - - if ($events === false) { - return; - } - - foreach ($events as $event) { - $startdate = $calendartype->timestamp_to_date_array($event->timestart); - if ($event->timeduration) { - $enddate = $calendartype->timestamp_to_date_array($event->timestart + $event->timeduration - 1); - } else { - $enddate = $startdate; - } - - // Simple arithmetic: $year * 13 + $month is a distinct integer for each distinct ($year, $month) pair. - if (!($startdate['year'] * 13 + $startdate['mon'] <= $year * 13 + $month) && - ($enddate['year'] * 13 + $enddate['mon'] >= $year * 13 + $month)) { - continue; - } - - $eventdaystart = intval($startdate['mday']); - - if ($startdate['mon'] == $month && $startdate['year'] == $year) { - // Give the event to its day. - $eventsbyday[$eventdaystart][] = $event->id; - - // Mark the day as having such an event. - if ($event->courseid == SITEID && $event->groupid == 0) { - $typesbyday[$eventdaystart]['startglobal'] = true; - // Set event class for global event. - $events[$event->id]->class = 'calendar_event_global'; - } else if ($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { - $typesbyday[$eventdaystart]['startcourse'] = true; - // Set event class for course event. - $events[$event->id]->class = 'calendar_event_course'; - } else if ($event->groupid) { - $typesbyday[$eventdaystart]['startgroup'] = true; - // Set event class for group event. - $events[$event->id]->class = 'calendar_event_group'; - } else if ($event->userid) { - $typesbyday[$eventdaystart]['startuser'] = true; - // Set event class for user event. - $events[$event->id]->class = 'calendar_event_user'; - } - } - - if ($event->timeduration == 0) { - // Proceed with the next. - continue; - } - - // The event starts on $month $year or before. - if ($startdate['mon'] == $month && $startdate['year'] == $year) { - $lowerbound = intval($startdate['mday']); - } else { - $lowerbound = 0; - } - - // Also, it ends on $month $year or later. - if ($enddate['mon'] == $month && $enddate['year'] == $year) { - $upperbound = intval($enddate['mday']); - } else { - $upperbound = self::get_days_in_month($month, $year); - } - - // Mark all days between $lowerbound and $upperbound (inclusive) as duration. - for ($i = $lowerbound + 1; $i <= $upperbound; ++$i) { - $durationbyday[$i][] = $event->id; - if ($event->courseid == SITEID && $event->groupid == 0) { - $typesbyday[$i]['durationglobal'] = true; - } else if ($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { - $typesbyday[$i]['durationcourse'] = true; - } else if ($event->groupid) { - $typesbyday[$i]['durationgroup'] = true; - } else if ($event->userid) { - $typesbyday[$i]['durationuser'] = true; - } - } - - } - return; - } - - /** - * Returns the courses to load events for, the - * - * @param array $courseeventsfrom An array of courses to load calendar events for - * @param bool $ignorefilters specify the use of filters, false is set as default - * @return array An array of courses, groups, and user to load calendar events for based upon filters - */ - public static function set_filters(array $courseeventsfrom, $ignorefilters = false) { - global $USER, $CFG; - - // For backwards compatability we have to check whether the courses array contains - // just id's in which case we need to load course objects. - $coursestoload = array(); - foreach ($courseeventsfrom as $id => $something) { - if (!is_object($something)) { - $coursestoload[] = $id; - unset($courseeventsfrom[$id]); - } - } - - $courses = array(); - $user = false; - $group = false; - - // Get the capabilities that allow seeing group events from all groups. - $allgroupscaps = array('moodle/site:accessallgroups', 'moodle/calendar:manageentries'); - - $isloggedin = isloggedin(); - - if ($ignorefilters || self::show_event_type(CALENDAR_EVENT_COURSE)) { - $courses = array_keys($courseeventsfrom); - } - if ($ignorefilters || self::show_event_type(CALENDAR_EVENT_GLOBAL)) { - $courses[] = SITEID; - } - $courses = array_unique($courses); - sort($courses); - - if (!empty($courses) && in_array(SITEID, $courses)) { - // Sort courses for consistent colour highlighting. - // Effectively ignoring SITEID as setting as last course id. - $key = array_search(SITEID, $courses); - unset($courses[$key]); - $courses[] = SITEID; - } - - if ($ignorefilters || ($isloggedin && self::show_event_type(CALENDAR_EVENT_USER))) { - $user = $USER->id; - } - - if (!empty($courseeventsfrom) && (self::show_event_type(CALENDAR_EVENT_GROUP) || $ignorefilters)) { - - if (count($courseeventsfrom) == 1) { - $course = reset($courseeventsfrom); - if (has_any_capability($allgroupscaps, \context_course::instance($course->id))) { - $coursegroups = groups_get_all_groups($course->id, 0, 0, 'g.id'); - $group = array_keys($coursegroups); - } - } - if ($group === false) { - if (!empty($CFG->calendar_adminseesall) && has_any_capability($allgroupscaps, \context_system::instance())) { - $group = true; - } else if ($isloggedin) { - $groupids = array(); - foreach ($courseeventsfrom as $courseid => $course) { - // If the user is an editing teacher in there. - if (!empty($USER->groupmember[$course->id])) { - // We've already cached the users groups for this course so we can just use that. - $groupids = array_merge($groupids, $USER->groupmember[$course->id]); - } else if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) { - // If this course has groups, show events from all of those related to the current user. - $coursegroups = groups_get_user_groups($course->id, $USER->id); - $groupids = array_merge($groupids, $coursegroups['0']); - } - } - if (!empty($groupids)) { - $group = $groupids; - } - } - } - } - if (empty($courses)) { - $courses = false; - } - - return array($courses, $group, $user); - } - - /** - * Return the capability for editing calendar event - * - * @param \calendar_event $event event object - * @return bool capability to edit event - */ - public static function can_edit_event($event) { - global $USER, $DB; - - // Must be logged in. - if (!isloggedin()) { - return false; - } - - // Can not be using guest account. - if (isguestuser()) { - return false; - } - - // You cannot edit calendar subscription events presently. - if (!empty($event->subscriptionid)) { - if (!empty($event->subscription->url)) { - // This event can be updated externally, so it cannot be edited. - return false; - } - } - - $sitecontext = \context_system::instance(); - - // If user has manageentries at site level, return true. - if (has_capability('moodle/calendar:manageentries', $sitecontext)) { - return true; - } - - // If groupid is set, it's definitely a group event. - if (!empty($event->groupid)) { - // Allow users to add/edit group events if - - // 1) They have manageentries for the course OR - // 2) They have managegroupentries AND are in the group. - $group = $DB->get_record('groups', array('id' => $event->groupid)); - return $group && ( - has_capability('moodle/calendar:manageentries', $event->context) || - (has_capability('moodle/calendar:managegroupentries', $event->context) - && groups_is_member($event->groupid))); - } else if (!empty($event->courseid)) { - // If groupid is not set, but course is set, it's definiely a course event. - return has_capability('moodle/calendar:manageentries', $event->context); - } else if (!empty($event->userid) && $event->userid == $USER->id) { - // If course is not set, but userid id set, it's a user event. - return (has_capability('moodle/calendar:manageownentries', $event->context)); - } else if (!empty($event->userid)) { - return (has_capability('moodle/calendar:manageentries', $event->context)); - } - - return false; - } - - /** - * Returns the default courses to display on the calendar when there isn't a specific - * course to display. - * - * @return array $courses Array of courses to display - */ - public static function get_default_courses() { - global $CFG, $DB; - - if (!isloggedin()) { - return array(); - } - - if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', \context_system::instance())) { - $select = ', ' . \context_helper::get_preload_record_columns_sql('ctx'); - $join = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; - $sql = "SELECT c.* $select - FROM {course} c - $join - WHERE EXISTS (SELECT 1 FROM {event} e WHERE e.courseid = c.id) - "; - $courses = $DB->get_records_sql($sql, array('contextlevel' => CONTEXT_COURSE), 0, 20); - foreach ($courses as $course) { - \context_helper::preload_from_record($course); - } - return $courses; - } - - $courses = enrol_get_my_courses(); - - return $courses; - } - - /** - * Get event format time - * - * @param \calendar_event $event event object - * @param int $now current time in gmt - * @param array $linkparams list of params for event link - * @param bool $usecommonwords the words as formatted date/time. - * @param int $showtime determine the show time GMT timestamp - * @return string $eventtime link/string for event time - */ - public static function get_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime = 0) { - $starttime = $event->timestart; - $endtime = $event->timestart + $event->timeduration; - - if (empty($linkparams) || !is_array($linkparams)) { - $linkparams = array(); - } - - $linkparams['view'] = 'day'; - - // OK, now to get a meaningful display. - // Check if there is a duration for this event. - if ($event->timeduration) { - // Get the midnight of the day the event will start. - $usermidnightstart = usergetmidnight($starttime); - // Get the midnight of the day the event will end. - $usermidnightend = usergetmidnight($endtime); - // Check if we will still be on the same day. - if ($usermidnightstart == $usermidnightend) { - // Check if we are running all day. - if ($event->timeduration == DAYSECS) { - $time = get_string('allday', 'calendar'); - } else { // Specify the time we will be running this from. - $datestart = self::get_time_representation($starttime); - $dateend = self::get_time_representation($endtime); - $time = $datestart . ' » ' . $dateend; - } - - // Set printable representation. - if (!$showtime) { - $day = self::get_day_representation($event->timestart, $now, $usecommonwords); - $url = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); - $eventtime = \html_writer::link($url, $day) . ', ' . $time; - } else { - $eventtime = $time; - } - } else { // It must spans two or more days. - $daystart = self::get_day_representation($event->timestart, $now, $usecommonwords) . ', '; - if ($showtime == $usermidnightstart) { - $daystart = ''; - } - $timestart = self::get_time_representation($event->timestart); - $dayend = self::get_day_representation($event->timestart + $event->timeduration, $now, $usecommonwords) . ', '; - if ($showtime == $usermidnightend) { - $dayend = ''; - } - $timeend = self::get_time_representation($event->timestart + $event->timeduration); - - // Set printable representation. - if ($now >= $usermidnightstart && $now < strtotime('+1 day', $usermidnightstart)) { - $url = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); - $eventtime = $timestart . ' » ' . \html_writer::link($url, $dayend) . $timeend; - } else { - // The event is in the future, print start and end links. - $url = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $starttime); - $eventtime = \html_writer::link($url, $daystart) . $timestart . ' » '; - - $url = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); - $eventtime .= \html_writer::link($url, $dayend) . $timeend; - } - } - } else { // There is no time duration. - $time = self::get_time_representation($event->timestart); - // Set printable representation. - if (!$showtime) { - $day = self::get_day_representation($event->timestart, $now, $usecommonwords); - $url = self::get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $starttime); - $eventtime = \html_writer::link($url, $day) . ', ' . trim($time); - } else { - $eventtime = $time; - } - } - - // Check if It has expired. - if ($event->timestart + $event->timeduration < $now) { - $eventtime = '' . str_replace(' href=', ' class="dimmed" href=', $eventtime) . ''; - } - - return $eventtime; - } - - /** - * Checks to see if the requested type of event should be shown for the given user. - * - * @param int $type The type to check the display for (default is to display all) - * @param \stdClass|int|null $user The user to check for - by default the current user - * @return bool True if the tyep should be displayed false otherwise - */ - public static function show_event_type($type, $user = null) { - $default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER; - - if (get_user_preferences('calendar_persistflt', 0, $user) === 0) { - global $SESSION; - if (!isset($SESSION->calendarshoweventtype)) { - $SESSION->calendarshoweventtype = $default; - } - return $SESSION->calendarshoweventtype & $type; - } else { - return get_user_preferences('calendar_savedflt', $default, $user) & $type; - } - } - - /** - * Sets the display of the event type given $display. - * - * If $display = true the event type will be shown. - * If $display = false the event type will NOT be shown. - * If $display = null the current value will be toggled and saved. - * - * @param int $type object of CALENDAR_EVENT_XXX - * @param bool $display option to display event type - * @param \stdClass|int $user moodle user object or id, null means current user - */ - public static function set_event_type_display($type, $display = null, $user = null) { - $persist = get_user_preferences('calendar_persistflt', 0, $user); - $default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER; - if ($persist === 0) { - global $SESSION; - if (!isset($SESSION->calendarshoweventtype)) { - $SESSION->calendarshoweventtype = $default; - } - $preference = $SESSION->calendarshoweventtype; - } else { - $preference = get_user_preferences('calendar_savedflt', $default, $user); - } - $current = $preference & $type; - if ($display === null) { - $display = !$current; - } - if ($display && !$current) { - $preference += $type; - } else if (!$display && $current) { - $preference -= $type; - } - if ($persist === 0) { - $SESSION->calendarshoweventtype = $preference; - } else { - if ($preference == $default) { - unset_user_preference('calendar_savedflt', $user); - } else { - set_user_preference('calendar_savedflt', $preference, $user); - } - } - } - - /** - * Get calendar's allowed types - * - * @param \stdClass $allowed list of allowed edit for event type - * @param \stdClass|int $course object of a course or course id - */ - public static function get_allowed_types(&$allowed, $course = null) { - global $USER, $DB; - - $allowed = new \stdClass(); - $allowed->user = has_capability('moodle/calendar:manageownentries', \context_system::instance()); - $allowed->groups = false; - $allowed->courses = false; - $allowed->site = has_capability('moodle/calendar:manageentries', \context_course::instance(SITEID)); - - if (!empty($course)) { - if (!is_object($course)) { - $course = $DB->get_record('course', array('id' => $course), '*', MUST_EXIST); - } - if ($course->id != SITEID) { - $coursecontext = \context_course::instance($course->id); - $allowed->user = has_capability('moodle/calendar:manageownentries', $coursecontext); - - if (has_capability('moodle/calendar:manageentries', $coursecontext)) { - $allowed->courses = array($course->id => 1); - - if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) { - if (has_capability('moodle/site:accessallgroups', $coursecontext)) { - $allowed->groups = groups_get_all_groups($course->id); - } else { - $allowed->groups = groups_get_all_groups($course->id, $USER->id); - } - } - } else if (has_capability('moodle/calendar:managegroupentries', $coursecontext)) { - if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) { - if (has_capability('moodle/site:accessallgroups', $coursecontext)) { - $allowed->groups = groups_get_all_groups($course->id); - } else { - $allowed->groups = groups_get_all_groups($course->id, $USER->id); - } - } - } - } - } - } - - /** - * See if user can add calendar entries at all - * used to print the "New Event" button - * - * @param \stdClass $course object of a course or course id - * @return bool has the capability to add at least one event type - */ - public static function can_add_event_to_course($course) { - if (!isloggedin() || isguestuser()) { - return false; - } - - self::get_allowed_types($allowed, $course); - - return (bool)($allowed->user || $allowed->groups || $allowed->courses || $allowed->site); - } - - /** - * Check wether the current user is permitted to add events - * - * @param \stdClass $event object of event - * @return bool has the capability to add event - */ - public static function can_add_event($event) { - global $USER, $DB; - - // Can not be using guest account. - if (!isloggedin() or isguestuser()) { - return false; - } - - $sitecontext = \context_system::instance(); - - // If user has manageentries at site level, always return true. - if (has_capability('moodle/calendar:manageentries', $sitecontext)) { - return true; - } - - switch ($event->eventtype) { - case 'course': - return has_capability('moodle/calendar:manageentries', $event->context); - case 'group': - // Allow users to add/edit group events if - - // 1) They have manageentries (= entries for whole course). - // 2) They have managegroupentries AND are in the group. - $group = $DB->get_record('groups', array('id' => $event->groupid)); - return $group && ( - has_capability('moodle/calendar:manageentries', $event->context) || - (has_capability('moodle/calendar:managegroupentries', $event->context) - && groups_is_member($event->groupid))); - case 'user': - if ($event->userid == $USER->id) { - return (has_capability('moodle/calendar:manageownentries', $event->context)); - } - // There is intentionally no 'break'. - case 'site': - return has_capability('moodle/calendar:manageentries', $event->context); - default: - return has_capability('moodle/calendar:manageentries', $event->context); - } - } - - /** - * Returns option list for the poll interval setting. - * - * @return array An array of poll interval options. Interval => description. - */ - public static function get_poll_interval_choices() { - return array( - '0' => new \lang_string('never', 'calendar'), - HOURSECS => new \lang_string('hourly', 'calendar'), - DAYSECS => new \lang_string('daily', 'calendar'), - WEEKSECS => new \lang_string('weekly', 'calendar'), - '2628000' => new \lang_string('monthly', 'calendar'), - YEARSECS => new \lang_string('annually', 'calendar') - ); - } - - /** - * Returns option list of available options for the calendar event type, given the current user and course. - * - * @param int $courseid The id of the course - * @return array An array containing the event types the user can create. - */ - public static function get_event_type_choices($courseid) { - $choices = array(); - $allowed = new \stdClass; - self::get_allowed_types($allowed, $courseid); - - if ($allowed->user) { - $choices['user'] = get_string('userevents', 'calendar'); - } - if ($allowed->site) { - $choices['site'] = get_string('siteevents', 'calendar'); - } - if (!empty($allowed->courses)) { - $choices['course'] = get_string('courseevents', 'calendar'); - } - if (!empty($allowed->groups) and is_array($allowed->groups)) { - $choices['group'] = get_string('group'); - } - - return array($choices, $allowed->groups); - } - - /** - * Add an iCalendar subscription to the database. - * - * @param \stdClass $sub The subscription object (e.g. from the form) - * @return int The insert ID, if any. - */ - public static function add_subscription($sub) { - global $DB, $USER, $SITE; - - if ($sub->eventtype === 'site') { - $sub->courseid = $SITE->id; - } else if ($sub->eventtype === 'group' || $sub->eventtype === 'course') { - $sub->courseid = $sub->course; - } else { - // User events. - $sub->courseid = 0; - } - $sub->userid = $USER->id; - - // File subscriptions never update. - if (empty($sub->url)) { - $sub->pollinterval = 0; - } - - if (!empty($sub->name)) { - if (empty($sub->id)) { - $id = $DB->insert_record('event_subscriptions', $sub); - // We cannot cache the data here because $sub is not complete. - $sub->id = $id; - // Trigger event, calendar subscription added. - $eventparams = array('objectid' => $sub->id, - 'context' => self::get_calendar_context($sub), - 'other' => array('eventtype' => $sub->eventtype, 'courseid' => $sub->courseid) - ); - $event = \core\event\calendar_subscription_created::create($eventparams); - $event->trigger(); - return $id; - } else { - // Why are we doing an update here? - self::update_subscription($sub); - return $sub->id; - } - } else { - print_error('errorbadsubscription', 'importcalendar'); - } - } - - /** - * Add an iCalendar event to the Moodle calendar. - * - * @param \stdClass $event The RFC-2445 iCalendar event - * @param int $courseid The course ID - * @param int $subscriptionid The iCalendar subscription ID - * @param string $timezone The X-WR-TIMEZONE iCalendar property if provided - * @return int Code: CALENDAR_IMPORT_EVENT_UPDATED = updated, CALENDAR_IMPORT_EVENT_INSERTED = inserted, 0 = error - */ - public static function add_icalendar_event($event, $courseid, $subscriptionid, $timezone='UTC') { - global $DB; - - // Probably an unsupported X-MICROSOFT-CDO-BUSYSTATUS event. - if (empty($event->properties['SUMMARY'])) { - return 0; - } - - $name = $event->properties['SUMMARY'][0]->value; - $name = str_replace('\n', '
', $name); - $name = str_replace('\\', '', $name); - $name = preg_replace('/\s+/u', ' ', $name); - - $eventrecord = new \stdClass; - $eventrecord->name = clean_param($name, PARAM_NOTAGS); - - if (empty($event->properties['DESCRIPTION'][0]->value)) { - $description = ''; - } else { - $description = $event->properties['DESCRIPTION'][0]->value; - $description = clean_param($description, PARAM_NOTAGS); - $description = str_replace('\n', '
', $description); - $description = str_replace('\\', '', $description); - $description = preg_replace('/\s+/u', ' ', $description); - } - $eventrecord->description = $description; - - // Probably a repeating event with RRULE etc. TODO: skip for now. - if (empty($event->properties['DTSTART'][0]->value)) { - return 0; - } - - if (isset($event->properties['DTSTART'][0]->parameters['TZID'])) { - $tz = $event->properties['DTSTART'][0]->parameters['TZID']; - } else { - $tz = $timezone; - } - $tz = \core_date::normalise_timezone($tz); - $eventrecord->timestart = strtotime($event->properties['DTSTART'][0]->value . ' ' . $tz); - if (empty($event->properties['DTEND'])) { - $eventrecord->timeduration = 0; // No duration if no end time specified. - } else { - if (isset($event->properties['DTEND'][0]->parameters['TZID'])) { - $endtz = $event->properties['DTEND'][0]->parameters['TZID']; - } else { - $endtz = $timezone; - } - $endtz = \core_date::normalise_timezone($endtz); - $eventrecord->timeduration = strtotime($event->properties['DTEND'][0]->value . ' ' . $endtz) - $eventrecord->timestart; - } - - // Check to see if it should be treated as an all day event. - if ($eventrecord->timeduration == DAYSECS) { - // Check to see if the event started at Midnight on the imported calendar. - date_default_timezone_set($timezone); - if (date('H:i:s', $eventrecord->timestart) === "00:00:00") { - // This event should be an all day event. - $eventrecord->timeduration = 0; - } - \core_date::set_default_server_timezone(); - } - - $eventrecord->uuid = $event->properties['UID'][0]->value; - $eventrecord->timemodified = time(); - - // Add the iCal subscription details if required. - // We should never do anything with an event without a subscription reference. - $sub = self::get_subscription($subscriptionid); - $eventrecord->subscriptionid = $subscriptionid; - $eventrecord->userid = $sub->userid; - $eventrecord->groupid = $sub->groupid; - $eventrecord->courseid = $sub->courseid; - $eventrecord->eventtype = $sub->eventtype; - - if ($updaterecord = $DB->get_record('event', array('uuid' => $eventrecord->uuid, - 'subscriptionid' => $eventrecord->subscriptionid))) { - $eventrecord->id = $updaterecord->id; - $return = CALENDAR_IMPORT_EVENT_UPDATED; // Update. - } else { - $return = CALENDAR_IMPORT_EVENT_INSERTED; // Insert. - } - if ($createdevent = \calendar_event::create($eventrecord, false)) { - if (!empty($event->properties['RRULE'])) { - // Repeating events. - date_default_timezone_set($tz); // Change time zone to parse all events. - $rrule = new rrule_manager($event->properties['RRULE'][0]->value); - $rrule->parse_rrule(); - $rrule->create_events($createdevent); - \core_date::set_default_server_timezone(); // Change time zone back to what it was. - } - return $return; - } else { - return 0; - } - } - - /** - * Update a subscription from the form data in one of the rows in the existing subscriptions table. - * - * @param int $subscriptionid The ID of the subscription we are acting upon. - * @param int $pollinterval The poll interval to use. - * @param int $action The action to be performed. One of update or remove. - * @return string A log of the import progress, including errors - */ - public static function process_subscription_row($subscriptionid, $pollinterval, $action) { - // Fetch the subscription from the database making sure it exists. - $sub = self::get_subscription($subscriptionid); - - // Update or remove the subscription, based on action. - switch ($action) { - case CALENDAR_SUBSCRIPTION_UPDATE: - // Skip updating file subscriptions. - if (empty($sub->url)) { - break; - } - $sub->pollinterval = $pollinterval; - self::update_subscription($sub); - - // Update the events. - return "

" . get_string('subscriptionupdated', 'calendar', $sub->name) . "

" . - self::update_subscription_events($subscriptionid); - case CALENDAR_SUBSCRIPTION_REMOVE: - self::delete_subscription($subscriptionid); - return get_string('subscriptionremoved', 'calendar', $sub->name); - break; - default: - break; - } - return ''; - } - - /** - * Delete subscription and all related events. - * - * @param int|\stdClass $subscription subscription or it's id, which needs to be deleted. - */ - public static function delete_subscription($subscription) { - global $DB; - - if (!is_object($subscription)) { - $subscription = $DB->get_record('event_subscriptions', array('id' => $subscription), '*', MUST_EXIST); - } - - // Delete subscription and related events. - $DB->delete_records('event', array('subscriptionid' => $subscription->id)); - $DB->delete_records('event_subscriptions', array('id' => $subscription->id)); - \cache_helper::invalidate_by_definition('core', 'calendar_subscriptions', array(), array($subscription->id)); - - // Trigger event, calendar subscription deleted. - $eventparams = array('objectid' => $subscription->id, - 'context' => self::get_calendar_context($subscription), - 'other' => array('courseid' => $subscription->courseid) - ); - $event = \core\event\calendar_subscription_deleted::create($eventparams); - $event->trigger(); - } - - /** - * From a URL, fetch the calendar and return an iCalendar object. - * - * @param string $url The iCalendar URL - * @return \iCalendar The iCalendar object - * @throws \moodle_exception - */ - public static function get_icalendar($url) { - global $CFG; - - require_once($CFG->libdir . '/filelib.php'); - - $curl = new \curl(); - $curl->setopt(array('CURLOPT_FOLLOWLOCATION' => 1, 'CURLOPT_MAXREDIRS' => 5)); - $calendar = $curl->get($url); - - // Http code validation should actually be the job of curl class. - if (!$calendar || $curl->info['http_code'] != 200 || !empty($curl->errorno)) { - throw new \moodle_exception('errorinvalidicalurl', 'calendar'); - } - - $ical = new \iCalendar(); - $ical->unserialize($calendar); - - return $ical; - } - - /** - * Import events from an iCalendar object into a course calendar. - * - * @param \iCalendar $ical The iCalendar object. - * @param int $courseid The course ID for the calendar. - * @param int $subscriptionid The subscription ID. - * @return string A log of the import progress, including errors. - */ - public static function import_icalendar_events($ical, $courseid, $subscriptionid = null) { - global $DB; - - $return = ''; - $eventcount = 0; - $updatecount = 0; - - // Large calendars take a while... - if (!CLI_SCRIPT) { - \core_php_time_limit::raise(300); - } - - // Mark all events in a subscription with a zero timestamp. - if (!empty($subscriptionid)) { - $sql = "UPDATE {event} SET timemodified = :time WHERE subscriptionid = :id"; - $DB->execute($sql, array('time' => 0, 'id' => $subscriptionid)); - } - - // Grab the timezone from the iCalendar file to be used later. - if (isset($ical->properties['X-WR-TIMEZONE'][0]->value)) { - $timezone = $ical->properties['X-WR-TIMEZONE'][0]->value; - } else { - $timezone = 'UTC'; - } - - $return = ''; - foreach ($ical->components['VEVENT'] as $event) { - $res = self::add_icalendar_event($event, $courseid, $subscriptionid, $timezone); - switch ($res) { - case CALENDAR_IMPORT_EVENT_UPDATED: - $updatecount++; - break; - case CALENDAR_IMPORT_EVENT_INSERTED: - $eventcount++; - break; - case 0: - $return .= '

' . get_string('erroraddingevent', 'calendar') . ': '; - if (empty($event->properties['SUMMARY'])) { - $return .= '(' . get_string('notitle', 'calendar') . ')'; - } else { - $return .= $event->properties['SUMMARY'][0]->value; - } - $return .= "

\n"; - break; - } - } - - $return .= "

" . get_string('eventsimported', 'calendar', $eventcount) . "

"; - $return .= "

" . get_string('eventsupdated', 'calendar', $updatecount) . "

"; - - // Delete remaining zero-marked events since they're not in remote calendar. - if (!empty($subscriptionid)) { - $deletecount = $DB->count_records('event', array('timemodified' => 0, 'subscriptionid' => $subscriptionid)); - if (!empty($deletecount)) { - $DB->delete_records('event', array('timemodified' => 0, 'subscriptionid' => $subscriptionid)); - $return .= "

" . get_string('eventsdeleted', 'calendar') . ": {$deletecount}

\n"; - } - } - - return $return; - } - - /** - * Fetch a calendar subscription and update the events in the calendar. - * - * @param int $subscriptionid The course ID for the calendar. - * @return string A log of the import progress, including errors. - */ - public static function update_subscription_events($subscriptionid) { - $sub = self::get_subscription($subscriptionid); - - // Don't update a file subscription. - if (empty($sub->url)) { - return 'File subscription not updated.'; - } - - $ical = self::get_icalendar($sub->url); - $return = self::import_icalendar_events($ical, $sub->courseid, $subscriptionid); - $sub->lastupdated = time(); - - self::update_subscription($sub); - - return $return; - } - - /** - * Update a calendar subscription. Also updates the associated cache. - * - * @param \stdClass|array $subscription Subscription record. - * @throws \coding_exception If something goes wrong - */ - public static function update_subscription($subscription) { - global $DB; - - if (is_array($subscription)) { - $subscription = (object)$subscription; - } - if (empty($subscription->id) || !$DB->record_exists('event_subscriptions', array('id' => $subscription->id))) { - throw new \coding_exception('Cannot update a subscription without a valid id'); - } - - $DB->update_record('event_subscriptions', $subscription); - - // Update cache. - $cache = \cache::make('core', 'calendar_subscriptions'); - $cache->set($subscription->id, $subscription); - - // Trigger event, calendar subscription updated. - $eventparams = array('userid' => $subscription->userid, - 'objectid' => $subscription->id, - 'context' => self::get_calendar_context($subscription), - 'other' => array('eventtype' => $subscription->eventtype, 'courseid' => $subscription->courseid) - ); - $event = \core\event\calendar_subscription_updated::create($eventparams); - $event->trigger(); - } - - /** - * Checks to see if the user can edit a given subscription feed. - * - * @param mixed $subscriptionorid Subscription object or id - * @return bool true if current user can edit the subscription else false - */ - public static function can_edit_subscription($subscriptionorid) { - if (is_array($subscriptionorid)) { - $subscription = (object)$subscriptionorid; - } else if (is_object($subscriptionorid)) { - $subscription = $subscriptionorid; - } else { - $subscription = self::get_subscription($subscriptionorid); - } - - $allowed = new \stdClass; - $courseid = $subscription->courseid; - $groupid = $subscription->groupid; - - self::get_allowed_types($allowed, $courseid); - switch ($subscription->eventtype) { - case 'user': - return $allowed->user; - case 'course': - if (isset($allowed->courses[$courseid])) { - return $allowed->courses[$courseid]; - } else { - return false; - } - case 'site': - return $allowed->site; - case 'group': - if (isset($allowed->groups[$groupid])) { - return $allowed->groups[$groupid]; - } else { - return false; - } - default: - return false; - } - } - - /** - * Helper function to determine the context of a calendar subscription. - * Subscriptions can be created in two contexts COURSE, or USER. - * - * @param \stdClass $subscription - * @return \context instance - */ - public static function get_calendar_context($subscription) { - // Determine context based on calendar type. - if ($subscription->eventtype === 'site') { - $context = \context_course::instance(SITEID); - } else if ($subscription->eventtype === 'group' || $subscription->eventtype === 'course') { - $context = \context_course::instance($subscription->courseid); - } else { - $context = \context_user::instance($subscription->userid); - } - return $context; - } - /** * Get a list of action events for the logged in user by the given * timesort values. diff --git a/calendar/classes/local/event/factories/event_abstract_factory.php b/calendar/classes/local/event/factories/event_abstract_factory.php index 1fb2e3d28d1..5f55e287059 100644 --- a/calendar/classes/local/event/factories/event_abstract_factory.php +++ b/calendar/classes/local/event/factories/event_abstract_factory.php @@ -134,12 +134,12 @@ abstract class event_abstract_factory implements event_factory_interface { } $course = new std_proxy($dbrow->courseid, function($id) { - return \core_calendar\api::get_course_cached($this->coursecachereference, $id); + return calendar_get_course_cached($this->coursecachereference, $id); }); if ($dbrow->groupid) { $group = new std_proxy($dbrow->groupid, function($id) { - return \core_calendar\api::get_group_cached($id); + return calendar_get_group_cached($id); }); } @@ -155,7 +155,7 @@ abstract class event_abstract_factory implements event_factory_interface { $dbrow->modulename, $dbrow->instance, function($modulename, $instance) { - return \core_calendar\api::get_module_cached( + return calendar_get_module_cached( $this->modulecachereference, $modulename, $instance @@ -166,7 +166,7 @@ abstract class event_abstract_factory implements event_factory_interface { if ($dbrow->subscriptionid) { $subscription = new std_proxy($dbrow->subscriptionid, function($id) { - return \core_calendar\api::get_subscription($id); + return calendar_get_subscription($id); }); } diff --git a/calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php b/calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php index 13ea2513f94..dc888f234c8 100644 --- a/calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php +++ b/calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php @@ -159,10 +159,10 @@ class raw_event_retrieval_strategy implements raw_event_retrieval_strategy_inter $subqueryconditions = []; // Get the user's courses. Otherwise, get the default courses being shown by the calendar. - $usercourses = \core_calendar\api::get_default_courses(); + $usercourses = calendar_get_default_courses(); // Set calendar filters. - list($usercourses, $usergroups, $user) = \core_calendar\api::set_filters($usercourses, true); + list($usercourses, $usergroups, $user) = calendar_set_filters($usercourses, true); $subqueryparams = []; // Flag to indicate whether the query needs to exclude group overrides. diff --git a/calendar/delete.php b/calendar/delete.php index 6ebb06edf7f..93c6c4d6bce 100644 --- a/calendar/delete.php +++ b/calendar/delete.php @@ -59,7 +59,7 @@ if (!$course) { } // Check the user has the required capabilities to edit an event -if (!\core_calendar\api::can_edit_event($event)) { +if (!calendar_edit_event_allowed($event)) { print_error('nopermissions'); } diff --git a/calendar/event.php b/calendar/event.php index dcf655878d9..66c6a6f18b5 100644 --- a/calendar/event.php +++ b/calendar/event.php @@ -94,7 +94,7 @@ if ($courseid != SITEID && !empty($courseid)) { $issite = false; } else { $course = get_site(); - $courses = \core_calendar\api::get_default_courses(); + $courses = calendar_get_default_courses(); $issite = true; } require_login($course, false); @@ -114,7 +114,7 @@ $formoptions = new stdClass; if ($eventid !== 0) { $title = get_string('editevent', 'calendar'); $event = calendar_event::load($eventid); - if (!\core_calendar\api::can_edit_event($event)) { + if (!calendar_edit_event_allowed($event)) { print_error('nopermissions'); } $event->action = $action; @@ -122,7 +122,7 @@ if ($eventid !== 0) { $event->timedurationuntil = $event->timestart + $event->timeduration; $event->count_repeats(); - if (!\core_calendar\api::can_add_event($event)) { + if (!calendar_add_event_allowed($event)) { print_error('nopermissions'); } @@ -134,7 +134,7 @@ if ($eventid !== 0) { } else { $title = get_string('newevent', 'calendar'); - \core_calendar\api::get_allowed_types($formoptions->eventtypes, $course); + calendar_get_allowed_types($formoptions->eventtypes, $course); $event = new stdClass(); $event->action = $action; $event->course = $courseid; @@ -150,7 +150,7 @@ if ($eventid !== 0) { } $event->timestart = $time; $event = new calendar_event($event); - if (!\core_calendar\api::can_add_event($event)) { + if (!calendar_add_event_allowed($event)) { print_error('nopermissions'); } } diff --git a/calendar/export.php b/calendar/export.php index 302513a0cc7..979c89272b9 100644 --- a/calendar/export.php +++ b/calendar/export.php @@ -82,7 +82,7 @@ if ($courseid != SITEID && !empty($courseid)) { $issite = false; } else { $course = get_site(); - $courses = \core_calendar\api::get_default_courses(); + $courses = calendar_get_default_courses(); $issite = true; } require_course_login($course); @@ -108,7 +108,7 @@ if ($issite) { $PAGE->navbar->add($course->shortname, new moodle_url('/course/view.php', array('id'=>$course->id))); } $link = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$calendar->courseid)); -$PAGE->navbar->add(get_string('calendar', 'calendar'), \core_calendar\api::get_link_href($link, 0, 0, 0, $time)); +$PAGE->navbar->add(get_string('calendar', 'calendar'), calendar_get_link_href($link, 0, 0, 0, $time)); $PAGE->navbar->add($pagetitle); $PAGE->set_title($course->shortname.': '.get_string('calendar', 'calendar').': '.$pagetitle); @@ -133,7 +133,7 @@ $formdata = array( // If today it's weekend, give the "next week" option. 'allownextweek' => $weekend & (1 << $now['wday']), // If it's the last week of the month, give the "next month" option. - 'allownextmonth' => \core_calendar\api::get_days_in_month($now['mon'], $now['year']) - $now['mday'] < $numberofdaysinweek, + 'allownextmonth' => calendar_days_in_month($now['mon'], $now['year']) - $now['mday'] < $numberofdaysinweek, // If today it's weekend but tomorrow it isn't, do NOT give the "this week" option. 'allowthisweek' => !(($weekend & (1 << $now['wday'])) && !($weekend & (1 << (($now['wday'] + 1) % $numberofdaysinweek)))) ); diff --git a/calendar/export_execute.php b/calendar/export_execute.php index 6b300ce9a72..e3abec8ab83 100644 --- a/calendar/export_execute.php +++ b/calendar/export_execute.php @@ -60,7 +60,7 @@ if (!empty($generateurl)) { if(!empty($what) && !empty($time)) { if(in_array($what, $allowed_what) && in_array($time, $allowed_time)) { $courses = enrol_get_users_courses($user->id, true, 'id, visible, shortname'); - // Array of courses that we will pass to \core_calendar\api::get_events() which + // Array of courses that we will pass to calendar_get_events() which // is initially set to the list of the user's courses. $paramcourses = $courses; if ($what == 'all' || $what == 'groups') { @@ -95,12 +95,12 @@ if(!empty($what) && !empty($time)) { switch($time) { case 'weeknow': - $startweekday = \core_calendar\api::get_starting_weekday(); + $startweekday = calendar_get_starting_weekday(); $startmonthday = find_day_in_month($now['mday'] - ($numberofdaysinweek - 1), $startweekday, $now['mon'], $now['year']); $startmonth = $now['mon']; $startyear = $now['year']; - if ($startmonthday > \core_calendar\api::get_days_in_month($startmonth, $startyear)) { - list($startmonth, $startyear) = \core_calendar\api::get_next_month($startmonth, $startyear); + if ($startmonthday > calendar_days_in_month($startmonth, $startyear)) { + list($startmonth, $startyear) = calendar_add_month($startmonth, $startyear); $startmonthday = find_day_in_month(1, $startweekday, $startmonth, $startyear); } $gregoriandate = $calendartype->convert_to_gregorian($startyear, $startmonth, $startmonthday); @@ -110,8 +110,8 @@ if(!empty($what) && !empty($time)) { $endmonthday = $startmonthday + $numberofdaysinweek; $endmonth = $startmonth; $endyear = $startyear; - if ($endmonthday > \core_calendar\api::get_days_in_month($endmonth, $endyear)) { - list($endmonth, $endyear) = \core_calendar\api::get_next_month($endmonth, $endyear); + if ($endmonthday > calendar_days_in_month($endmonth, $endyear)) { + list($endmonth, $endyear) = calendar_add_month($endmonth, $endyear); $endmonthday = find_day_in_month(1, $startweekday, $endmonth, $endyear); } $gregoriandate = $calendartype->convert_to_gregorian($endyear, $endmonth, $endmonthday); @@ -119,12 +119,12 @@ if(!empty($what) && !empty($time)) { $gregoriandate['hour'], $gregoriandate['minute']); break; case 'weeknext': - $startweekday = \core_calendar\api::get_starting_weekday(); + $startweekday = calendar_get_starting_weekday(); $startmonthday = find_day_in_month($now['mday'] + 1, $startweekday, $now['mon'], $now['year']); $startmonth = $now['mon']; $startyear = $now['year']; - if ($startmonthday > \core_calendar\api::get_days_in_month($startmonth, $startyear)) { - list($startmonth, $startyear) = \core_calendar\api::get_next_month($startmonth, $startyear); + if ($startmonthday > calendar_days_in_month($startmonth, $startyear)) { + list($startmonth, $startyear) = calendar_add_month($startmonth, $startyear); $startmonthday = find_day_in_month(1, $startweekday, $startmonth, $startyear); } $gregoriandate = $calendartype->convert_to_gregorian($startyear, $startmonth, $startmonthday); @@ -134,8 +134,8 @@ if(!empty($what) && !empty($time)) { $endmonthday = $startmonthday + $numberofdaysinweek; $endmonth = $startmonth; $endyear = $startyear; - if ($endmonthday > \core_calendar\api::get_days_in_month($endmonth, $endyear)) { - list($endmonth, $endyear) = \core_calendar\api::get_next_month($endmonth, $endyear); + if ($endmonthday > calendar_days_in_month($endmonth, $endyear)) { + list($endmonth, $endyear) = calendar_add_month($endmonth, $endyear); $endmonthday = find_day_in_month(1, $startweekday, $endmonth, $endyear); } $gregoriandate = $calendartype->convert_to_gregorian($endyear, $endmonth, $endmonthday); @@ -148,11 +148,11 @@ if(!empty($what) && !empty($time)) { $timestart = make_timestamp($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'], $gregoriandate['hour'], $gregoriandate['minute']); - $timeend = $timestart + (\core_calendar\api::get_days_in_month($now['mon'], $now['year']) * DAYSECS); + $timeend = $timestart + (calendar_days_in_month($now['mon'], $now['year']) * DAYSECS); break; case 'monthnext': // Get the next month for this calendar. - list($nextmonth, $nextyear) = \core_calendar\api::get_next_month($now['mon'], $now['year']); + list($nextmonth, $nextyear) = calendar_add_month($now['mon'], $now['year']); // Convert to gregorian. $gregoriandate = $calendartype->convert_to_gregorian($nextyear, $nextmonth, 1); @@ -160,7 +160,7 @@ if(!empty($what) && !empty($time)) { // Create the timestamps. $timestart = make_timestamp($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'], $gregoriandate['hour'], $gregoriandate['minute']); - $timeend = $timestart + (\core_calendar\api::get_days_in_month($nextmonth, $nextyear) * DAYSECS); + $timeend = $timestart + (calendar_days_in_month($nextmonth, $nextyear) * DAYSECS); break; case 'recentupcoming': //Events in the last 5 or next 60 days @@ -180,7 +180,7 @@ if(!empty($what) && !empty($time)) { die(); } } -$events = \core_calendar\api::get_events($timestart, $timeend, $users, $groups, array_keys($paramcourses), false); +$events = calendar_get_events($timestart, $timeend, $users, $groups, array_keys($paramcourses), false); $ical = new iCalendar; $ical->add_property('method', 'PUBLISH'); diff --git a/calendar/externallib.php b/calendar/externallib.php index 6365dd2f721..c6208f4c3de 100644 --- a/calendar/externallib.php +++ b/calendar/externallib.php @@ -86,7 +86,7 @@ class core_calendar_external extends external_api { $eventobj = calendar_event::load($event['eventid']); // Let's check if the user is allowed to delete an event. - if (!\core_calendar\api::can_edit_event($eventobj)) { + if (!calendar_edit_event_allowed($eventobj)) { throw new moodle_exception("nopermissions"); } // Time to do the magic. @@ -233,14 +233,14 @@ class core_calendar_external extends external_api { } // Event list does not check visibility and permissions, we'll check that later. - $eventlist = \core_calendar\api::get_events($params['options']['timestart'], $params['options']['timeend'], + $eventlist = calendar_get_events($params['options']['timestart'], $params['options']['timeend'], $funcparam['users'], $funcparam['groups'], $funcparam['courses'], true, $params['options']['ignorehidden']); // WS expects arrays. $events = array(); // We need to get events asked for eventids. - if ($eventsbyid = \core_calendar\api::get_events_by_id($params['events']['eventids'])) { + if ($eventsbyid = calendar_get_events_by_id($params['events']['eventids'])) { $eventlist += $eventsbyid; } @@ -265,7 +265,7 @@ class core_calendar_external extends external_api { (!empty($eventobj->groupid) && in_array($eventobj->groupid, $groups)) || (!empty($eventobj->courseid) && in_array($eventobj->courseid, $courses)) || ($USER->id == $eventobj->userid) || - (\core_calendar\api::can_edit_event($eventid))) { + (calendar_edit_event_allowed($eventid))) { $events[$eventid] = $event; } else { $warnings[] = array('item' => $eventid, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to view this event'); @@ -623,7 +623,7 @@ class core_calendar_external extends external_api { $eventobj = new calendar_event($event); // Let's check if the user is allowed to delete an event. - if (!\core_calendar\api::can_add_event($eventobj)) { + if (!calendar_add_event_allowed($eventobj)) { $warnings [] = array('item' => $event['name'], 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to create this event'); continue; } diff --git a/calendar/lib.php b/calendar/lib.php index 9f885d576b0..8a7b200e605 100644 --- a/calendar/lib.php +++ b/calendar/lib.php @@ -210,7 +210,7 @@ class calendar_event { } if (!empty($data->subscriptionid)) { - $data->subscription = \core_calendar\api::get_subscription($data->subscriptionid); + $data->subscription = calendar_get_subscription($data->subscriptionid); } // Default to a user event. @@ -438,7 +438,7 @@ class calendar_event { if (empty($this->properties->id) || $this->properties->id < 1) { if ($checkcapability) { - if (!\core_calendar\api::can_add_event($this->properties)) { + if (!calendar_add_event_allowed($this->properties)) { print_error('nopermissiontoupdatecalendar'); } } @@ -549,7 +549,7 @@ class calendar_event { } else { if ($checkcapability) { - if (!\core_calendar\api::can_edit_event($this->properties)) { + if (!calendar_edit_event_allowed($this->properties)) { print_error('nopermissiontoupdatecalendar'); } } @@ -994,7 +994,7 @@ class calendar_information { public function prepare_for_view(stdClass $course, array $coursestoload, $ignorefilters = false) { $this->courseid = $course->id; $this->course = $course; - list($courses, $group, $user) = \core_calendar\api::set_filters($coursestoload, $ignorefilters); + list($courses, $group, $user) = calendar_set_filters($coursestoload, $ignorefilters); $this->courses = $courses; $this->groups = $group; $this->users = $user; @@ -1163,10 +1163,10 @@ function calendar_get_events($tstart, $tend, $users, $groups, $courses, $withdur $subqueryconditions = []; // Get the user's courses. Otherwise, get the default courses being shown by the calendar. - $usercourses = \core_calendar\api::get_default_courses(); + $usercourses = calendar_get_default_courses(); // Set calendar filters. - list($usercourses, $usergroups, $user) = \core_calendar\api::set_filters($usercourses, true); + list($usercourses, $usergroups, $user) = calendar_set_filters($usercourses, true); $subqueryparams = []; // Flag to indicate whether the query needs to exclude group overrides. @@ -1265,7 +1265,8 @@ function calendar_get_events($tstart, $tend, $users, $groups, $courses, $withdur * @return array array of days */ function calendar_get_days() { - return \core_calendar\api::get_days(); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_weekdays(); } /** @@ -1277,7 +1278,16 @@ function calendar_get_days() { * @throws moodle_exception for an invalid id */ function calendar_get_subscription($id) { - return \core_calendar\api::get_subscription($id); + global $DB; + + $cache = \cache::make('core', 'calendar_subscriptions'); + $subscription = $cache->get($id); + if (empty($subscription)) { + $subscription = $DB->get_record('event_subscriptions', array('id' => $id), '*', MUST_EXIST); + $cache->set($id, $subscription); + } + + return $subscription; } /** @@ -1288,7 +1298,8 @@ function calendar_get_subscription($id) { * @return int */ function calendar_get_starting_weekday() { - return \core_calendar\api::get_starting_weekday(); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_starting_weekday(); } /** @@ -1307,8 +1318,335 @@ function calendar_get_starting_weekday() { */ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyear = false, $placement = false, $courseid = false, $time = 0) { - return \core_calendar\api::get_mini_calendar($courses, $groups, $users, $calmonth, $calyear, $placement, - $courseid, $time); + global $CFG, $OUTPUT; + + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + + $display = new \stdClass; + + // Assume we are not displaying this month for now. + $display->thismonth = false; + + $content = ''; + + // Do this check for backwards compatibility. + // The core should be passing a timestamp rather than month and year. + // If a month and year are passed they will be in Gregorian. + if (!empty($calmonth) && !empty($calyear)) { + // Ensure it is a valid date, else we will just set it to the current timestamp. + if (checkdate($calmonth, 1, $calyear)) { + $time = make_timestamp($calyear, $calmonth, 1); + } else { + $time = time(); + } + $date = usergetdate($time); + if ($calmonth == $date['mon'] && $calyear == $date['year']) { + $display->thismonth = true; + } + // We can overwrite date now with the date used by the calendar type, + // if it is not Gregorian, otherwise there is no need as it is already in Gregorian. + if ($calendartype->get_name() != 'gregorian') { + $date = $calendartype->timestamp_to_date_array($time); + } + } else if (!empty($time)) { + // Get the specified date in the calendar type being used. + $date = $calendartype->timestamp_to_date_array($time); + $thisdate = $calendartype->timestamp_to_date_array(time()); + if ($date['month'] == $thisdate['month'] && $date['year'] == $thisdate['year']) { + $display->thismonth = true; + // If we are the current month we want to set the date to the current date, not the start of the month. + $date = $thisdate; + } + } else { + // Get the current date in the calendar type being used. + $time = time(); + $date = $calendartype->timestamp_to_date_array($time); + $display->thismonth = true; + } + + list($d, $m, $y) = array($date['mday'], $date['mon'], $date['year']); // This is what we want to display. + + // Get Gregorian date for the start of the month. + $gregoriandate = $calendartype->convert_to_gregorian($date['year'], $date['mon'], 1); + + // Store the gregorian date values to be used later. + list($gy, $gm, $gd, $gh, $gmin) = array($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'], + $gregoriandate['hour'], $gregoriandate['minute']); + + // Get the max number of days in this month for this calendar type. + $display->maxdays = calendar_days_in_month($m, $y); + // Get the starting week day for this month. + $startwday = dayofweek(1, $m, $y); + // Get the days in a week. + $daynames = calendar_get_days(); + // Store the number of days in a week. + $numberofdaysinweek = $calendartype->get_num_weekdays(); + + // Set the min and max weekday. + $display->minwday = calendar_get_starting_weekday(); + $display->maxwday = $display->minwday + ($numberofdaysinweek - 1); + + // These are used for DB queries, so we want unixtime, so we need to use Gregorian dates. + $display->tstart = make_timestamp($gy, $gm, $gd, $gh, $gmin, 0); + $display->tend = $display->tstart + ($display->maxdays * DAYSECS) - 1; + + // Align the starting weekday to fall in our display range. + // This is simple, not foolproof. + if ($startwday < $display->minwday) { + $startwday += $numberofdaysinweek; + } + + // Get the events matching our criteria. Don't forget to offset the timestamps for the user's TZ. + $events = calendar_get_events($display->tstart, $display->tend, $users, $groups, $courses); + + // Set event course class for course events. + if (!empty($events)) { + foreach ($events as $eventid => $event) { + if (!empty($event->modulename)) { + $cm = get_coursemodule_from_instance($event->modulename, $event->instance); + if (!\core_availability\info_module::is_user_visible($cm, 0, false)) { + unset($events[$eventid]); + } + } + } + } + + // This is either a genius idea or an idiot idea: in order to not complicate things, we use this rule: if, after + // possibly removing SITEID from $courses, there is only one course left, then clicking on a day in the month + // will also set the $SESSION->cal_courses_shown variable to that one course. Otherwise, we 'd need to add extra + // arguments to this function. + $hrefparams = array(); + if (!empty($courses)) { + $courses = array_diff($courses, array(SITEID)); + if (count($courses) == 1) { + $hrefparams['course'] = reset($courses); + } + } + + // We want to have easy access by day, since the display is on a per-day basis. + calendar_events_by_day($events, $m, $y, $eventsbyday, $durationbyday, $typesbyday, $courses); + + // Accessibility: added summary and elements. + $summary = get_string('calendarheading', 'calendar', userdate($display->tstart, get_string('strftimemonthyear'))); + // Begin table. + $content .= ''; + if (($placement !== false) && ($courseid !== false)) { + $content .= ''; + } + $content .= ''; // Header row: day names. + + // Print out the names of the weekdays. + for ($i = $display->minwday; $i <= $display->maxwday; $i++) { + $pos = $i % $numberofdaysinweek; + $content .= '\n"; + } + + $content .= ''; // End of day names; prepare for day numbers. + + // For the table display. $week is the row; $dayweek is the column. + $dayweek = $startwday; + + // Padding (the first week may have blank days in the beginning). + for ($i = $display->minwday; $i < $startwday; ++$i) { + $content .= '' ."\n"; + } + + $weekend = CALENDAR_DEFAULT_WEEKEND; + if (isset($CFG->calendar_weekend)) { + $weekend = intval($CFG->calendar_weekend); + } + + // Now display all the calendar. + $daytime = strtotime('-1 day', $display->tstart); + for ($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) { + $cellattributes = array(); + $daytime = strtotime('+1 day', $daytime); + if ($dayweek > $display->maxwday) { + // We need to change week (table row). + $content .= ''; + $dayweek = $display->minwday; + } + + // Reset vars. + if ($weekend & (1 << ($dayweek % $numberofdaysinweek))) { + // Weekend. This is true no matter what the exact range is. + $class = 'weekend day'; + } else { + // Normal working day. + $class = 'day'; + } + + $eventids = array(); + if (!empty($eventsbyday[$day])) { + $eventids = $eventsbyday[$day]; + } + + if (!empty($durationbyday[$day])) { + $eventids = array_unique(array_merge($eventids, $durationbyday[$day])); + } + + $finishclass = false; + + if (!empty($eventids)) { + // There is at least one event on this day. + $class .= ' hasevent'; + $hrefparams['view'] = 'day'; + $dayhref = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $hrefparams), 0, 0, 0, $daytime); + + $popupcontent = ''; + foreach ($eventids as $eventid) { + if (!isset($events[$eventid])) { + continue; + } + $event = new \calendar_event($events[$eventid]); + $popupalt = ''; + $component = 'moodle'; + if (!empty($event->modulename)) { + $popupicon = 'icon'; + $popupalt = $event->modulename; + $component = $event->modulename; + } else if ($event->courseid == SITEID) { // Site event. + $popupicon = 'i/siteevent'; + } else if ($event->courseid != 0 && $event->courseid != SITEID + && $event->groupid == 0) { // Course event. + $popupicon = 'i/courseevent'; + } else if ($event->groupid) { // Group event. + $popupicon = 'i/groupevent'; + } else { // Must be a user event. + $popupicon = 'i/userevent'; + } + + if ($event->timeduration) { + $startdate = $calendartype->timestamp_to_date_array($event->timestart); + $enddate = $calendartype->timestamp_to_date_array($event->timestart + $event->timeduration - 1); + if ($enddate['mon'] == $m && $enddate['year'] == $y && $enddate['mday'] == $day) { + $finishclass = true; + } + } + + $dayhref->set_anchor('event_' . $event->id); + + $popupcontent .= \html_writer::start_tag('div'); + $popupcontent .= $OUTPUT->pix_icon($popupicon, $popupalt, $component); + // Show ical source if needed. + if (!empty($event->subscription) && $CFG->calendar_showicalsource) { + $a = new \stdClass(); + $a->name = format_string($event->name, true); + $a->source = $event->subscription->name; + $name = get_string('namewithsource', 'calendar', $a); + } else { + if ($finishclass) { + $samedate = $startdate['mon'] == $enddate['mon'] && + $startdate['year'] == $enddate['year'] && + $startdate['mday'] == $enddate['mday']; + + if ($samedate) { + $name = format_string($event->name, true); + } else { + $name = format_string($event->name, true) . ' (' . get_string('eventendtime', 'calendar') . ')'; + } + } else { + $name = format_string($event->name, true); + } + } + $popupcontent .= \html_writer::link($dayhref, $name); + $popupcontent .= \html_writer::end_tag('div'); + } + + if ($display->thismonth && $day == $d) { + $popupdata = calendar_get_popup(true, $daytime, $popupcontent); + } else { + $popupdata = calendar_get_popup(false, $daytime, $popupcontent); + } + + // Class and cell content. + if (isset($typesbyday[$day]['startglobal'])) { + $class .= ' calendar_event_global'; + } else if (isset($typesbyday[$day]['startcourse'])) { + $class .= ' calendar_event_course'; + } else if (isset($typesbyday[$day]['startgroup'])) { + $class .= ' calendar_event_group'; + } else if (isset($typesbyday[$day]['startuser'])) { + $class .= ' calendar_event_user'; + } + if ($finishclass) { + $class .= ' duration_finish'; + } + $data = array( + 'url' => $dayhref, + 'day' => $day, + 'content' => $popupdata['data-core_calendar-popupcontent'], + 'title' => $popupdata['data-core_calendar-title'] + ); + $cell = $OUTPUT->render_from_template('core_calendar/minicalendar_day_link', $data); + } else { + $cell = $day; + } + + $durationclass = false; + if (isset($typesbyday[$day]['durationglobal'])) { + $durationclass = ' duration_global'; + } else if (isset($typesbyday[$day]['durationcourse'])) { + $durationclass = ' duration_course'; + } else if (isset($typesbyday[$day]['durationgroup'])) { + $durationclass = ' duration_group'; + } else if (isset($typesbyday[$day]['durationuser'])) { + $durationclass = ' duration_user'; + } + if ($durationclass) { + $class .= ' duration ' . $durationclass; + } + + // If event has a class set then add it to the table day '; + } + $content .= ''; // Last row ends. + + $content .= '
' . calendar_top_controls($placement, + array('id' => $courseid, 'time' => $time)) . '
' . + $daynames[$pos]['shortname'] . "
 
tag. + // Note: only one colour for minicalendar. + if (isset($eventsbyday[$day])) { + foreach ($eventsbyday[$day] as $eventid) { + if (!isset($events[$eventid])) { + continue; + } + $event = $events[$eventid]; + if (!empty($event->class)) { + $class .= ' ' . $event->class; + } + break; + } + } + + if ($display->thismonth && $day == $d) { + // The current cell is for today - add appropriate classes and additional information for styling. + $class .= ' today'; + $today = get_string('today', 'calendar') . ' ' . userdate(time(), get_string('strftimedayshort')); + + if (!isset($eventsbyday[$day]) && !isset($durationbyday[$day])) { + $class .= ' eventnone'; + $popupdata = calendar_get_popup(true, false); + $data = array( + 'url' => '#', + 'day' => $day, + 'content' => $popupdata['data-core_calendar-popupcontent'], + 'title' => $popupdata['data-core_calendar-title'] + ); + $cell = $OUTPUT->render_from_template('core_calendar/minicalendar_day_link', $data); + } + $cell = get_accesshide($today . ' ') . $cell; + } + + // Just display it. + $cellattributes['class'] = $class; + $content .= \html_writer::tag('td', $cell, $cellattributes); + } + + // Padding (the last week may have blank days at the end). + for ($i = $dayweek; $i <= $display->maxwday; ++$i) { + $content .= ' 
'; // Tabular display of days ends. + return $content; } /** @@ -1323,7 +1661,23 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea * @return string eventid for the calendar_tooltip popup window/layout. */ function calendar_get_popup($today = false, $timestart, $popupcontent = '') { - return \core_calendar\api::get_popup($today, $timestart, $popupcontent); + $popupcaption = ''; + if ($today) { + $popupcaption = get_string('today', 'calendar') . ' '; + } + + if (false === $timestart) { + $popupcaption .= userdate(time(), get_string('strftimedayshort')); + $popupcontent = get_string('eventnone', 'calendar'); + + } else { + $popupcaption .= get_string('eventsfor', 'calendar', userdate($timestart, get_string('strftimedayshort'))); + } + + return array( + 'data-core_calendar-title' => $popupcaption, + 'data-core_calendar-popupcontent' => $popupcontent, + ); } /** @@ -1338,7 +1692,75 @@ function calendar_get_popup($today = false, $timestart, $popupcontent = '') { * @return array $output array of upcoming events */ function calendar_get_upcoming($courses, $groups, $users, $daysinfuture, $maxevents, $fromtime=0) { - return \core_calendar\api::get_upcoming($courses, $groups, $users, $daysinfuture, $maxevents, $fromtime); + global $COURSE; + + $display = new \stdClass; + $display->range = $daysinfuture; // How many days in the future we 'll look. + $display->maxevents = $maxevents; + + $output = array(); + + $processed = 0; + $now = time(); // We 'll need this later. + $usermidnighttoday = usergetmidnight($now); + + if ($fromtime) { + $display->tstart = $fromtime; + } else { + $display->tstart = $usermidnighttoday; + } + + // This works correctly with respect to the user's DST, but it is accurate + // only because $fromtime is always the exact midnight of some day! + $display->tend = usergetmidnight($display->tstart + DAYSECS * $display->range + 3 * HOURSECS) - 1; + + // Get the events matching our criteria. + $events = calendar_get_events($display->tstart, $display->tend, $users, $groups, $courses); + + // This is either a genius idea or an idiot idea: in order to not complicate things, we use this rule: if, after + // possibly removing SITEID from $courses, there is only one course left, then clicking on a day in the month + // will also set the $SESSION->cal_courses_shown variable to that one course. Otherwise, we 'd need to add extra + // arguments to this function. + $hrefparams = array(); + if (!empty($courses)) { + $courses = array_diff($courses, array(SITEID)); + if (count($courses) == 1) { + $hrefparams['course'] = reset($courses); + } + } + + if ($events !== false) { + $modinfo = get_fast_modinfo($COURSE); + foreach ($events as $event) { + if (!empty($event->modulename)) { + if ($event->courseid == $COURSE->id) { + if (isset($modinfo->instances[$event->modulename][$event->instance])) { + $cm = $modinfo->instances[$event->modulename][$event->instance]; + if (!$cm->uservisible) { + continue; + } + } + } else { + if (!$cm = get_coursemodule_from_instance($event->modulename, $event->instance)) { + continue; + } + if (!\core_availability\info_module::is_user_visible($cm, 0, false)) { + continue; + } + } + } + + if ($processed >= $display->maxevents) { + break; + } + + $event->time = calendar_format_event_time($event, $now, $hrefparams); + $output[] = $event; + $processed++; + } + } + + return $output; } /** @@ -1348,29 +1770,33 @@ function calendar_get_upcoming($courses, $groups, $users, $daysinfuture, $maxeve * @return string a link to the course (as HTML); empty if the course id is invalid */ function calendar_get_courselink($courseid) { - return \core_calendar\api::get_courselink($courseid); + if (!$courseid) { + return ''; + } + + calendar_get_course_cached($coursecache, $courseid); + $context = \context_course::instance($courseid); + $fullname = format_string($coursecache[$courseid]->fullname, true, array('context' => $context)); + $url = new \moodle_url('/course/view.php', array('id' => $courseid)); + $link = \html_writer::link($url, $fullname); + + return $link; } /** * Get current module cache. * - * @param array $coursecache list of course cache + * @param array $modulecache in memory module cache * @param string $modulename name of the module * @param int $instance module instance number * @return stdClass|bool $module information */ -function calendar_get_module_cached(&$coursecache, $modulename, $instance) { - // We have a new implementation of this function in the calendar API class, - // so the old implementation must remain here. - $module = get_coursemodule_from_instance($modulename, $instance); +function calendar_get_module_cached(&$modulecache, $modulename, $instance) { + if (!isset($modulecache[$modulename . '_' . $instance])) { + $modulecache[$modulename . '_' . $instance] = get_coursemodule_from_instance($modulename, $instance); + } - if ($module === false) { - return false; - } - if (!calendar_get_course_cached($coursecache, $module->course)) { - return false; - } - return $module; + return $modulecache[$modulename . '_' . $instance]; } /** @@ -1381,7 +1807,10 @@ function calendar_get_module_cached(&$coursecache, $modulename, $instance) { * @return stdClass $coursecache[$courseid] return the specific course cache */ function calendar_get_course_cached(&$coursecache, $courseid) { - return \core_calendar\api::get_course_cached($coursecache, $courseid); + if (!isset($coursecache[$courseid])) { + $coursecache[$courseid] = get_course($courseid); + } + return $coursecache[$courseid]; } /** @@ -1391,7 +1820,11 @@ function calendar_get_course_cached(&$coursecache, $courseid) { * @return stdClass group object with fields 'id', 'name' and 'courseid' */ function calendar_get_group_cached($groupid) { - return \core_calendar\api::get_group_cached($groupid); + static $groupscache = array(); + if (!isset($groupscache[$groupid])) { + $groupscache[$groupid] = groups_get_group($groupid, 'id,name,courseid'); + } + return $groupscache[$groupid]; } /** @@ -1401,7 +1834,61 @@ function calendar_get_group_cached($groupid) { * @return stdClass $event metadata */ function calendar_add_event_metadata($event) { - return \core_calendar\api::add_event_metadata($event); + global $CFG, $OUTPUT; + + // Support multilang in event->name. + $event->name = format_string($event->name, true); + + if (!empty($event->modulename)) { // Activity event. + // The module name is set. I will assume that it has to be displayed, and + // also that it is an automatically-generated event. And of course that the + // fields for get_coursemodule_from_instance are set correctly. + $module = calendar_get_module_cached($coursecache, $event->modulename, $event->instance); + + if ($module === false) { + return; + } + + $modulename = get_string('modulename', $event->modulename); + if (get_string_manager()->string_exists($event->eventtype, $event->modulename)) { + // Will be used as alt text if the event icon. + $eventtype = get_string($event->eventtype, $event->modulename); + } else { + $eventtype = ''; + } + $icon = $OUTPUT->image_url('icon', $event->modulename) . ''; + + $event->icon = '' . $eventtype . ''; + $event->referer = '' . $event->name . ''; + $event->courselink = calendar_get_courselink($module->course); + $event->cmid = $module->id; + } else if ($event->courseid == SITEID) { // Site event. + $event->icon = '' .
+            get_string('globalevent', 'calendar') . ''; + $event->cssclass = 'calendar_event_global'; + } else if ($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { // Course event. + $event->icon = '' .
+            get_string('courseevent', 'calendar') . ''; + $event->courselink = calendar_get_courselink($event->courseid); + $event->cssclass = 'calendar_event_course'; + } else if ($event->groupid) { // Group event. + if ($group = calendar_get_group_cached($event->groupid)) { + $groupname = format_string($group->name, true, \context_course::instance($group->courseid)); + } else { + $groupname = ''; + } + $event->icon = \html_writer::empty_tag('image', array('src' => $OUTPUT->image_url('i/groupevent'), + 'alt' => get_string('groupevent', 'calendar'), 'title' => $groupname, 'class' => 'icon')); + $event->courselink = calendar_get_courselink($event->courseid) . ', ' . $groupname; + $event->cssclass = 'calendar_event_group'; + } else if ($event->userid) { // User event. + $event->icon = '' .
+            get_string('userevent', 'calendar') . ''; + $event->cssclass = 'calendar_event_user'; + } + + return $event; } /** @@ -1412,7 +1899,16 @@ function calendar_add_event_metadata($event) { * @return array Array of event entries, empty array if nothing found */ function calendar_get_events_by_id($eventids) { - return \core_calendar\api::get_events_by_id($eventids); + global $DB; + + if (!is_array($eventids) || empty($eventids)) { + return array(); + } + + list($wheresql, $params) = $DB->get_in_or_equal($eventids); + $wheresql = "id $wheresql"; + + return $DB->get_records_select('event', $wheresql, $params); } /** @@ -1423,7 +1919,160 @@ function calendar_get_events_by_id($eventids) { * @return string $content return available control for the calender in html */ function calendar_top_controls($type, $data) { - return \core_calendar\api::get_top_controls($type, $data); + global $PAGE, $OUTPUT; + + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + + $content = ''; + + // Ensure course id passed if relevant. + $courseid = ''; + if (!empty($data['id'])) { + $courseid = '&course=' . $data['id']; + } + + // If we are passing a month and year then we need to convert this to a timestamp to + // support multiple calendars. No where in core should these be passed, this logic + // here is for third party plugins that may use this function. + if (!empty($data['m']) && !empty($date['y'])) { + if (!isset($data['d'])) { + $data['d'] = 1; + } + if (!checkdate($data['m'], $data['d'], $data['y'])) { + $time = time(); + } else { + $time = make_timestamp($data['y'], $data['m'], $data['d']); + } + } else if (!empty($data['time'])) { + $time = $data['time']; + } else { + $time = time(); + } + + // Get the date for the calendar type. + $date = $calendartype->timestamp_to_date_array($time); + + $urlbase = $PAGE->url; + + // We need to get the previous and next months in certain cases. + if ($type == 'frontpage' || $type == 'course' || $type == 'month') { + $prevmonth = calendar_sub_month($date['mon'], $date['year']); + $prevmonthtime = $calendartype->convert_to_gregorian($prevmonth[1], $prevmonth[0], 1); + $prevmonthtime = make_timestamp($prevmonthtime['year'], $prevmonthtime['month'], $prevmonthtime['day'], + $prevmonthtime['hour'], $prevmonthtime['minute']); + + $nextmonth = calendar_add_month($date['mon'], $date['year']); + $nextmonthtime = $calendartype->convert_to_gregorian($nextmonth[1], $nextmonth[0], 1); + $nextmonthtime = make_timestamp($nextmonthtime['year'], $nextmonthtime['month'], $nextmonthtime['day'], + $nextmonthtime['hour'], $nextmonthtime['minute']); + } + + switch ($type) { + case 'frontpage': + $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), $urlbase, false, false, false, + true, $prevmonthtime); + $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), $urlbase, false, false, false, true, + $nextmonthtime); + $calendarlink = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', array('view' => 'month')), + false, false, false, $time); + + if (!empty($data['id'])) { + $calendarlink->param('course', $data['id']); + } + + $right = $nextlink; + + $content .= \html_writer::start_tag('div', array('class' => 'calendar-controls')); + $content .= $prevlink . ' | '; + $content .= \html_writer::tag('span', \html_writer::link($calendarlink, + userdate($time, get_string('strftimemonthyear')), array('title' => get_string('monththis', 'calendar')) + ), array('class' => 'current')); + $content .= ' | ' . $right; + $content .= "\n"; + $content .= \html_writer::end_tag('div'); + + break; + case 'course': + $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), $urlbase, false, false, false, + true, $prevmonthtime); + $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), $urlbase, false, false, false, + true, $nextmonthtime); + $calendarlink = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', array('view' => 'month')), + false, false, false, $time); + + if (!empty($data['id'])) { + $calendarlink->param('course', $data['id']); + } + + $content .= \html_writer::start_tag('div', array('class' => 'calendar-controls')); + $content .= $prevlink . ' | '; + $content .= \html_writer::tag('span', \html_writer::link($calendarlink, + userdate($time, get_string('strftimemonthyear')), array('title' => get_string('monththis', 'calendar')) + ), array('class' => 'current')); + $content .= ' | ' . $nextlink; + $content .= ""; + $content .= \html_writer::end_tag('div'); + break; + case 'upcoming': + $calendarlink = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', array('view' => 'upcoming')), + false, false, false, $time); + if (!empty($data['id'])) { + $calendarlink->param('course', $data['id']); + } + $calendarlink = \html_writer::link($calendarlink, userdate($time, get_string('strftimemonthyear'))); + $content .= \html_writer::tag('div', $calendarlink, array('class' => 'centered')); + break; + case 'display': + $calendarlink = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', array('view' => 'month')), + false, false, false, $time); + if (!empty($data['id'])) { + $calendarlink->param('course', $data['id']); + } + $calendarlink = \html_writer::link($calendarlink, userdate($time, get_string('strftimemonthyear'))); + $content .= \html_writer::tag('h3', $calendarlink); + break; + case 'month': + $prevlink = calendar_get_link_previous(userdate($prevmonthtime, get_string('strftimemonthyear')), + 'view.php?view=month' . $courseid . '&', false, false, false, false, $prevmonthtime); + $nextlink = calendar_get_link_next(userdate($nextmonthtime, get_string('strftimemonthyear')), + 'view.php?view=month' . $courseid . '&', false, false, false, false, $nextmonthtime); + + $content .= \html_writer::start_tag('div', array('class' => 'calendar-controls')); + $content .= $prevlink . ' | '; + $content .= $OUTPUT->heading(userdate($time, get_string('strftimemonthyear')), 2, 'current'); + $content .= ' | ' . $nextlink; + $content .= ''; + $content .= \html_writer::end_tag('div')."\n"; + break; + case 'day': + $days = calendar_get_days(); + + $prevtimestamp = strtotime('-1 day', $time); + $nexttimestamp = strtotime('+1 day', $time); + + $prevdate = $calendartype->timestamp_to_date_array($prevtimestamp); + $nextdate = $calendartype->timestamp_to_date_array($nexttimestamp); + + $prevname = $days[$prevdate['wday']]['fullname']; + $nextname = $days[$nextdate['wday']]['fullname']; + $prevlink = calendar_get_link_previous($prevname, 'view.php?view=day' . $courseid . '&', false, false, + false, false, $prevtimestamp); + $nextlink = calendar_get_link_next($nextname, 'view.php?view=day' . $courseid . '&', false, false, false, + false, $nexttimestamp); + + $content .= \html_writer::start_tag('div', array('class' => 'calendar-controls')); + $content .= $prevlink; + $content .= ' | ' .userdate($time, + get_string('strftimedaydate')) . ''; + $content .= ' | ' . $nextlink; + $content .= ""; + $content .= \html_writer::end_tag('div') . "\n"; + + break; + } + + return $content; } /** @@ -1434,7 +2083,42 @@ function calendar_top_controls($type, $data) { * @return string html content of the element */ function calendar_filter_controls_element(moodle_url $url, $type) { - return \core_calendar\api::get_filter_controls_element($url, $type); + global $OUTPUT; + + switch ($type) { + case CALENDAR_EVENT_GLOBAL: + $typeforhumans = 'global'; + $class = 'calendar_event_global'; + break; + case CALENDAR_EVENT_COURSE: + $typeforhumans = 'course'; + $class = 'calendar_event_course'; + break; + case CALENDAR_EVENT_GROUP: + $typeforhumans = 'groups'; + $class = 'calendar_event_group'; + break; + case CALENDAR_EVENT_USER: + $typeforhumans = 'user'; + $class = 'calendar_event_user'; + break; + } + + if (calendar_show_event_type($type)) { + $icon = $OUTPUT->pix_icon('t/hide', get_string('hide')); + $str = get_string('hide' . $typeforhumans . 'events', 'calendar'); + } else { + $icon = $OUTPUT->pix_icon('t/show', get_string('show')); + $str = get_string('show' . $typeforhumans . 'events', 'calendar'); + } + $content = \html_writer::start_tag('li', array('class' => 'calendar_event')); + $content .= \html_writer::start_tag('a', array('href' => $url, 'rel' => 'nofollow')); + $content .= \html_writer::tag('span', $icon, array('class' => $class)); + $content .= \html_writer::tag('span', $str, array('class' => 'eventname')); + $content .= \html_writer::end_tag('a'); + $content .= \html_writer::end_tag('li'); + + return $content; } /** @@ -1447,7 +2131,30 @@ function calendar_filter_controls_element(moodle_url $url, $type) { * @return string $content return filter controls in html */ function calendar_filter_controls(moodle_url $returnurl) { - return \core_calendar\api::get_filter_controls($returnurl); + $groupevents = true; + + $seturl = new \moodle_url('/calendar/set.php', array('return' => base64_encode($returnurl->out_as_local_url(false)), + 'sesskey' => sesskey())); + $content = \html_writer::start_tag('ul'); + + $seturl->param('var', 'showglobal'); + $content .= calendar_filter_controls_element($seturl, CALENDAR_EVENT_GLOBAL); + + $seturl->param('var', 'showcourses'); + $content .= calendar_filter_controls_element($seturl, CALENDAR_EVENT_COURSE); + + if (isloggedin() && !isguestuser()) { + if ($groupevents) { + // This course MIGHT have group events defined, so show the filter. + $seturl->param('var', 'showgroups'); + $content .= calendar_filter_controls_element($seturl, CALENDAR_EVENT_GROUP); + } + $seturl->param('var', 'showuser'); + $content .= calendar_filter_controls_element($seturl, CALENDAR_EVENT_USER); + } + $content .= \html_writer::end_tag('ul'); + + return $content; } /** @@ -1459,7 +2166,38 @@ function calendar_filter_controls(moodle_url $returnurl) { * @return string the formatted date/time */ function calendar_day_representation($tstamp, $now = false, $usecommonwords = true) { - return \core_calendar\api::get_day_representation($tstamp, $now, $usecommonwords); + static $shortformat; + + if (empty($shortformat)) { + $shortformat = get_string('strftimedayshort'); + } + + if ($now === false) { + $now = time(); + } + + // To have it in one place, if a change is needed. + $formal = userdate($tstamp, $shortformat); + + $datestamp = usergetdate($tstamp); + $datenow = usergetdate($now); + + if ($usecommonwords == false) { + // We don't want words, just a date. + return $formal; + } else if ($datestamp['year'] == $datenow['year'] && $datestamp['yday'] == $datenow['yday']) { + return get_string('today', 'calendar'); + } else if (($datestamp['year'] == $datenow['year'] && $datestamp['yday'] == $datenow['yday'] - 1 ) || + ($datestamp['year'] == $datenow['year'] - 1 && $datestamp['mday'] == 31 && $datestamp['mon'] == 12 + && $datenow['yday'] == 1)) { + return get_string('yesterday', 'calendar'); + } else if (($datestamp['year'] == $datenow['year'] && $datestamp['yday'] == $datenow['yday'] + 1 ) || + ($datestamp['year'] == $datenow['year'] + 1 && $datenow['mday'] == 31 && $datenow['mon'] == 12 + && $datestamp['yday'] == 1)) { + return get_string('tomorrow', 'calendar'); + } else { + return $formal; + } } /** @@ -1470,7 +2208,18 @@ function calendar_day_representation($tstamp, $now = false, $usecommonwords = tr * @return string the formatted date/time */ function calendar_time_representation($time) { - return \core_calendar\api::get_time_representation($time); + static $langtimeformat = null; + + if ($langtimeformat === null) { + $langtimeformat = get_string('strftimetime'); + } + + $timeformat = get_user_preferences('calendar_timeformat'); + if (empty($timeformat)) { + $timeformat = get_config(null, 'calendar_site_timeformat'); + } + + return userdate($time, empty($timeformat) ? $langtimeformat : $timeformat); } /** @@ -1485,7 +2234,30 @@ function calendar_time_representation($time) { * @return moodle_url|null $linkbase */ function calendar_get_link_href($linkbase, $d, $m, $y, $time = 0) { - return \core_calendar\api::get_link_href($linkbase, $d, $m, $y, $time); + if (empty($linkbase)) { + return null; + } + + if (!($linkbase instanceof \moodle_url)) { + $linkbase = new \moodle_url($linkbase); + } + + // If a day, month and year were passed then convert it to a timestamp. If these were passed + // then we can assume the day, month and year are passed as Gregorian, as no where in core + // should we be passing these values rather than the time. + if (!empty($d) && !empty($m) && !empty($y)) { + if (checkdate($m, $d, $y)) { + $time = make_timestamp($y, $m, $d); + } else { + $time = time(); + } + } else if (empty($time)) { + $time = time(); + } + + $linkbase->param('time', $time); + + return $linkbase; } /** @@ -1502,7 +2274,13 @@ function calendar_get_link_href($linkbase, $d, $m, $y, $time = 0) { * @return string HTML string. */ function calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide = false, $time = 0) { - return \core_calendar\api::get_link_previous($text, $linkbase, $d, $m, $y, $accesshide, $time); + $href = calendar_get_link_href(new \moodle_url($linkbase), $d, $m, $y, $time); + + if (empty($href)) { + return $text; + } + + return link_arrow_left($text, (string)$href, $accesshide, 'previous'); } /** @@ -1519,7 +2297,13 @@ function calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide = * @return string HTML string. */ function calendar_get_link_next($text, $linkbase, $d, $m, $y, $accesshide = false, $time = 0) { - return \core_calendar\api::get_link_next($text, $linkbase, $d, $m, $y, $accesshide, $time); + $href = calendar_get_link_href(new \moodle_url($linkbase), $d, $m, $y, $time); + + if (empty($href)) { + return $text; + } + + return link_arrow_right($text, (string)$href, $accesshide, 'next'); } /** @@ -1530,7 +2314,8 @@ function calendar_get_link_next($text, $linkbase, $d, $m, $y, $accesshide = fals * @return int */ function calendar_days_in_month($month, $year) { - return \core_calendar\api::get_days_in_month($month, $year); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_num_days_in_month($year, $month); } /** @@ -1541,7 +2326,8 @@ function calendar_days_in_month($month, $year) { * @return array the following month */ function calendar_add_month($month, $year) { - return \core_calendar\api::get_next_month($month, $year); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_next_month($year, $month); } /** @@ -1552,7 +2338,8 @@ function calendar_add_month($month, $year) { * @return array previous month */ function calendar_sub_month($month, $year) { - return \core_calendar\api::get_prev_month($month, $year); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_prev_month($year, $month); } /** @@ -1568,7 +2355,91 @@ function calendar_sub_month($month, $year) { * @return void */ function calendar_events_by_day($events, $month, $year, &$eventsbyday, &$durationbyday, &$typesbyday, &$courses) { - \core_calendar\api::get_events_by_day($events, $month, $year, $eventsbyday, $durationbyday, $typesbyday, $courses); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + + $eventsbyday = array(); + $typesbyday = array(); + $durationbyday = array(); + + if ($events === false) { + return; + } + + foreach ($events as $event) { + $startdate = $calendartype->timestamp_to_date_array($event->timestart); + if ($event->timeduration) { + $enddate = $calendartype->timestamp_to_date_array($event->timestart + $event->timeduration - 1); + } else { + $enddate = $startdate; + } + + // Simple arithmetic: $year * 13 + $month is a distinct integer for each distinct ($year, $month) pair. + if (!($startdate['year'] * 13 + $startdate['mon'] <= $year * 13 + $month) && + ($enddate['year'] * 13 + $enddate['mon'] >= $year * 13 + $month)) { + continue; + } + + $eventdaystart = intval($startdate['mday']); + + if ($startdate['mon'] == $month && $startdate['year'] == $year) { + // Give the event to its day. + $eventsbyday[$eventdaystart][] = $event->id; + + // Mark the day as having such an event. + if ($event->courseid == SITEID && $event->groupid == 0) { + $typesbyday[$eventdaystart]['startglobal'] = true; + // Set event class for global event. + $events[$event->id]->class = 'calendar_event_global'; + } else if ($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { + $typesbyday[$eventdaystart]['startcourse'] = true; + // Set event class for course event. + $events[$event->id]->class = 'calendar_event_course'; + } else if ($event->groupid) { + $typesbyday[$eventdaystart]['startgroup'] = true; + // Set event class for group event. + $events[$event->id]->class = 'calendar_event_group'; + } else if ($event->userid) { + $typesbyday[$eventdaystart]['startuser'] = true; + // Set event class for user event. + $events[$event->id]->class = 'calendar_event_user'; + } + } + + if ($event->timeduration == 0) { + // Proceed with the next. + continue; + } + + // The event starts on $month $year or before. + if ($startdate['mon'] == $month && $startdate['year'] == $year) { + $lowerbound = intval($startdate['mday']); + } else { + $lowerbound = 0; + } + + // Also, it ends on $month $year or later. + if ($enddate['mon'] == $month && $enddate['year'] == $year) { + $upperbound = intval($enddate['mday']); + } else { + $upperbound = calendar_days_in_month($month, $year); + } + + // Mark all days between $lowerbound and $upperbound (inclusive) as duration. + for ($i = $lowerbound + 1; $i <= $upperbound; ++$i) { + $durationbyday[$i][] = $event->id; + if ($event->courseid == SITEID && $event->groupid == 0) { + $typesbyday[$i]['durationglobal'] = true; + } else if ($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { + $typesbyday[$i]['durationcourse'] = true; + } else if ($event->groupid) { + $typesbyday[$i]['durationgroup'] = true; + } else if ($event->userid) { + $typesbyday[$i]['durationuser'] = true; + } + } + + } + return; } /** @@ -1579,7 +2450,84 @@ function calendar_events_by_day($events, $month, $year, &$eventsbyday, &$duratio * @return array An array of courses, groups, and user to load calendar events for based upon filters */ function calendar_set_filters(array $courseeventsfrom, $ignorefilters = false) { - return \core_calendar\api::set_filters($courseeventsfrom, $ignorefilters); + global $USER, $CFG; + + // For backwards compatability we have to check whether the courses array contains + // just id's in which case we need to load course objects. + $coursestoload = array(); + foreach ($courseeventsfrom as $id => $something) { + if (!is_object($something)) { + $coursestoload[] = $id; + unset($courseeventsfrom[$id]); + } + } + + $courses = array(); + $user = false; + $group = false; + + // Get the capabilities that allow seeing group events from all groups. + $allgroupscaps = array('moodle/site:accessallgroups', 'moodle/calendar:manageentries'); + + $isloggedin = isloggedin(); + + if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_COURSE)) { + $courses = array_keys($courseeventsfrom); + } + if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) { + $courses[] = SITEID; + } + $courses = array_unique($courses); + sort($courses); + + if (!empty($courses) && in_array(SITEID, $courses)) { + // Sort courses for consistent colour highlighting. + // Effectively ignoring SITEID as setting as last course id. + $key = array_search(SITEID, $courses); + unset($courses[$key]); + $courses[] = SITEID; + } + + if ($ignorefilters || ($isloggedin && calendar_show_event_type(CALENDAR_EVENT_USER))) { + $user = $USER->id; + } + + if (!empty($courseeventsfrom) && (calendar_show_event_type(CALENDAR_EVENT_GROUP) || $ignorefilters)) { + + if (count($courseeventsfrom) == 1) { + $course = reset($courseeventsfrom); + if (has_any_capability($allgroupscaps, \context_course::instance($course->id))) { + $coursegroups = groups_get_all_groups($course->id, 0, 0, 'g.id'); + $group = array_keys($coursegroups); + } + } + if ($group === false) { + if (!empty($CFG->calendar_adminseesall) && has_any_capability($allgroupscaps, \context_system::instance())) { + $group = true; + } else if ($isloggedin) { + $groupids = array(); + foreach ($courseeventsfrom as $courseid => $course) { + // If the user is an editing teacher in there. + if (!empty($USER->groupmember[$course->id])) { + // We've already cached the users groups for this course so we can just use that. + $groupids = array_merge($groupids, $USER->groupmember[$course->id]); + } else if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) { + // If this course has groups, show events from all of those related to the current user. + $coursegroups = groups_get_user_groups($course->id, $USER->id); + $groupids = array_merge($groupids, $coursegroups['0']); + } + } + if (!empty($groupids)) { + $group = $groupids; + } + } + } + } + if (empty($courses)) { + $courses = false; + } + + return array($courses, $group, $user); } /** @@ -1589,7 +2537,54 @@ function calendar_set_filters(array $courseeventsfrom, $ignorefilters = false) { * @return bool capability to edit event */ function calendar_edit_event_allowed($event) { - return \core_calendar\api::can_edit_event($event); + global $USER, $DB; + + // Must be logged in. + if (!isloggedin()) { + return false; + } + + // Can not be using guest account. + if (isguestuser()) { + return false; + } + + // You cannot edit URL based calendar subscription events presently. + if (!empty($event->subscriptionid)) { + if (!empty($event->subscription->url)) { + // This event can be updated externally, so it cannot be edited. + return false; + } + } + + $sitecontext = \context_system::instance(); + + // If user has manageentries at site level, return true. + if (has_capability('moodle/calendar:manageentries', $sitecontext)) { + return true; + } + + // If groupid is set, it's definitely a group event. + if (!empty($event->groupid)) { + // Allow users to add/edit group events if - + // 1) They have manageentries for the course OR + // 2) They have managegroupentries AND are in the group. + $group = $DB->get_record('groups', array('id' => $event->groupid)); + return $group && ( + has_capability('moodle/calendar:manageentries', $event->context) || + (has_capability('moodle/calendar:managegroupentries', $event->context) + && groups_is_member($event->groupid))); + } else if (!empty($event->courseid)) { + // If groupid is not set, but course is set, it's definiely a course event. + return has_capability('moodle/calendar:manageentries', $event->context); + } else if (!empty($event->userid) && $event->userid == $USER->id) { + // If course is not set, but userid id set, it's a user event. + return (has_capability('moodle/calendar:manageownentries', $event->context)); + } else if (!empty($event->userid)) { + return (has_capability('moodle/calendar:manageentries', $event->context)); + } + + return false; } /** @@ -1599,7 +2594,30 @@ function calendar_edit_event_allowed($event) { * @return array $courses Array of courses to display */ function calendar_get_default_courses() { - return \core_calendar\api::get_default_courses(); + global $CFG, $DB; + + if (!isloggedin()) { + return array(); + } + + if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', \context_system::instance())) { + $select = ', ' . \context_helper::get_preload_record_columns_sql('ctx'); + $join = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; + $sql = "SELECT c.* $select + FROM {course} c + $join + WHERE EXISTS (SELECT 1 FROM {event} e WHERE e.courseid = c.id) + "; + $courses = $DB->get_records_sql($sql, array('contextlevel' => CONTEXT_COURSE), 0, 20); + foreach ($courses as $course) { + \context_helper::preload_from_record($course); + } + return $courses; + } + + $courses = enrol_get_my_courses(); + + return $courses; } /** @@ -1613,7 +2631,84 @@ function calendar_get_default_courses() { * @return string $eventtime link/string for event time */ function calendar_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime = 0) { - return \core_calendar\api::get_format_event_time($event, $now, $linkparams, $usecommonwords, $showtime); + $starttime = $event->timestart; + $endtime = $event->timestart + $event->timeduration; + + if (empty($linkparams) || !is_array($linkparams)) { + $linkparams = array(); + } + + $linkparams['view'] = 'day'; + + // OK, now to get a meaningful display. + // Check if there is a duration for this event. + if ($event->timeduration) { + // Get the midnight of the day the event will start. + $usermidnightstart = usergetmidnight($starttime); + // Get the midnight of the day the event will end. + $usermidnightend = usergetmidnight($endtime); + // Check if we will still be on the same day. + if ($usermidnightstart == $usermidnightend) { + // Check if we are running all day. + if ($event->timeduration == DAYSECS) { + $time = get_string('allday', 'calendar'); + } else { // Specify the time we will be running this from. + $datestart = calendar_time_representation($starttime); + $dateend = calendar_time_representation($endtime); + $time = $datestart . ' » ' . $dateend; + } + + // Set printable representation. + if (!$showtime) { + $day = calendar_day_representation($event->timestart, $now, $usecommonwords); + $url = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); + $eventtime = \html_writer::link($url, $day) . ', ' . $time; + } else { + $eventtime = $time; + } + } else { // It must spans two or more days. + $daystart = calendar_day_representation($event->timestart, $now, $usecommonwords) . ', '; + if ($showtime == $usermidnightstart) { + $daystart = ''; + } + $timestart = calendar_time_representation($event->timestart); + $dayend = calendar_day_representation($event->timestart + $event->timeduration, $now, $usecommonwords) . ', '; + if ($showtime == $usermidnightend) { + $dayend = ''; + } + $timeend = calendar_time_representation($event->timestart + $event->timeduration); + + // Set printable representation. + if ($now >= $usermidnightstart && $now < strtotime('+1 day', $usermidnightstart)) { + $url = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); + $eventtime = $timestart . ' » ' . \html_writer::link($url, $dayend) . $timeend; + } else { + // The event is in the future, print start and end links. + $url = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $starttime); + $eventtime = \html_writer::link($url, $daystart) . $timestart . ' » '; + + $url = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); + $eventtime .= \html_writer::link($url, $dayend) . $timeend; + } + } + } else { // There is no time duration. + $time = calendar_time_representation($event->timestart); + // Set printable representation. + if (!$showtime) { + $day = calendar_day_representation($event->timestart, $now, $usecommonwords); + $url = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $starttime); + $eventtime = \html_writer::link($url, $day) . ', ' . trim($time); + } else { + $eventtime = $time; + } + } + + // Check if It has expired. + if ($event->timestart + $event->timeduration < $now) { + $eventtime = '' . str_replace(' href=', ' class="dimmed" href=', $eventtime) . ''; + } + + return $eventtime; } /** @@ -1624,7 +2719,17 @@ function calendar_format_event_time($event, $now, $linkparams = null, $usecommon * @return bool True if the tyep should be displayed false otherwise */ function calendar_show_event_type($type, $user = null) { - return \core_calendar\api::show_event_type($type, $user); + $default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER; + + if (get_user_preferences('calendar_persistflt', 0, $user) === 0) { + global $SESSION; + if (!isset($SESSION->calendarshoweventtype)) { + $SESSION->calendarshoweventtype = $default; + } + return $SESSION->calendarshoweventtype & $type; + } else { + return get_user_preferences('calendar_savedflt', $default, $user) & $type; + } } /** @@ -1639,7 +2744,35 @@ function calendar_show_event_type($type, $user = null) { * @param stdClass|int $user moodle user object or id, null means current user */ function calendar_set_event_type_display($type, $display = null, $user = null) { - \core_calendar\api::set_event_type_display($type, $display, $user); + $persist = get_user_preferences('calendar_persistflt', 0, $user); + $default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER; + if ($persist === 0) { + global $SESSION; + if (!isset($SESSION->calendarshoweventtype)) { + $SESSION->calendarshoweventtype = $default; + } + $preference = $SESSION->calendarshoweventtype; + } else { + $preference = get_user_preferences('calendar_savedflt', $default, $user); + } + $current = $preference & $type; + if ($display === null) { + $display = !$current; + } + if ($display && !$current) { + $preference += $type; + } else if (!$display && $current) { + $preference -= $type; + } + if ($persist === 0) { + $SESSION->calendarshoweventtype = $preference; + } else { + if ($preference == $default) { + unset_user_preference('calendar_savedflt', $user); + } else { + set_user_preference('calendar_savedflt', $preference, $user); + } + } } /** @@ -1649,7 +2782,43 @@ function calendar_set_event_type_display($type, $display = null, $user = null) { * @param stdClass|int $course object of a course or course id */ function calendar_get_allowed_types(&$allowed, $course = null) { - \core_calendar\api::get_allowed_types($allowed, $course); + global $USER, $DB; + + $allowed = new \stdClass(); + $allowed->user = has_capability('moodle/calendar:manageownentries', \context_system::instance()); + $allowed->groups = false; + $allowed->courses = false; + $allowed->site = has_capability('moodle/calendar:manageentries', \context_course::instance(SITEID)); + + if (!empty($course)) { + if (!is_object($course)) { + $course = $DB->get_record('course', array('id' => $course), '*', MUST_EXIST); + } + if ($course->id != SITEID) { + $coursecontext = \context_course::instance($course->id); + $allowed->user = has_capability('moodle/calendar:manageownentries', $coursecontext); + + if (has_capability('moodle/calendar:manageentries', $coursecontext)) { + $allowed->courses = array($course->id => 1); + + if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) { + if (has_capability('moodle/site:accessallgroups', $coursecontext)) { + $allowed->groups = groups_get_all_groups($course->id); + } else { + $allowed->groups = groups_get_all_groups($course->id, $USER->id); + } + } + } else if (has_capability('moodle/calendar:managegroupentries', $coursecontext)) { + if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) { + if (has_capability('moodle/site:accessallgroups', $coursecontext)) { + $allowed->groups = groups_get_all_groups($course->id); + } else { + $allowed->groups = groups_get_all_groups($course->id, $USER->id); + } + } + } + } + } } /** @@ -1659,7 +2828,13 @@ function calendar_get_allowed_types(&$allowed, $course = null) { * @return bool has the capability to add at least one event type */ function calendar_user_can_add_event($course) { - return \core_calendar\api::can_add_event_to_course($course); + if (!isloggedin() || isguestuser()) { + return false; + } + + calendar_get_allowed_types($allowed, $course); + + return (bool)($allowed->user || $allowed->groups || $allowed->courses || $allowed->site); } /** @@ -1669,7 +2844,42 @@ function calendar_user_can_add_event($course) { * @return bool has the capability to add event */ function calendar_add_event_allowed($event) { - return \core_calendar\api::can_add_event($event); + global $USER, $DB; + + // Can not be using guest account. + if (!isloggedin() or isguestuser()) { + return false; + } + + $sitecontext = \context_system::instance(); + + // If user has manageentries at site level, always return true. + if (has_capability('moodle/calendar:manageentries', $sitecontext)) { + return true; + } + + switch ($event->eventtype) { + case 'course': + return has_capability('moodle/calendar:manageentries', $event->context); + case 'group': + // Allow users to add/edit group events if - + // 1) They have manageentries (= entries for whole course). + // 2) They have managegroupentries AND are in the group. + $group = $DB->get_record('groups', array('id' => $event->groupid)); + return $group && ( + has_capability('moodle/calendar:manageentries', $event->context) || + (has_capability('moodle/calendar:managegroupentries', $event->context) + && groups_is_member($event->groupid))); + case 'user': + if ($event->userid == $USER->id) { + return (has_capability('moodle/calendar:manageownentries', $event->context)); + } + // There is intentionally no 'break'. + case 'site': + return has_capability('moodle/calendar:manageentries', $event->context); + default: + return has_capability('moodle/calendar:manageentries', $event->context); + } } /** @@ -1678,7 +2888,14 @@ function calendar_add_event_allowed($event) { * @return array An array of poll interval options. Interval => description. */ function calendar_get_pollinterval_choices() { - return \core_calendar\api::get_poll_interval_choices(); + return array( + '0' => new \lang_string('never', 'calendar'), + HOURSECS => new \lang_string('hourly', 'calendar'), + DAYSECS => new \lang_string('daily', 'calendar'), + WEEKSECS => new \lang_string('weekly', 'calendar'), + '2628000' => new \lang_string('monthly', 'calendar'), + YEARSECS => new \lang_string('annually', 'calendar') + ); } /** @@ -1688,7 +2905,24 @@ function calendar_get_pollinterval_choices() { * @return array An array containing the event types the user can create. */ function calendar_get_eventtype_choices($courseid) { - return \core_calendar\api::get_event_type_choices($courseid); + $choices = array(); + $allowed = new \stdClass; + calendar_get_allowed_types($allowed, $courseid); + + if ($allowed->user) { + $choices['user'] = get_string('userevents', 'calendar'); + } + if ($allowed->site) { + $choices['site'] = get_string('siteevents', 'calendar'); + } + if (!empty($allowed->courses)) { + $choices['course'] = get_string('courseevents', 'calendar'); + } + if (!empty($allowed->groups) and is_array($allowed->groups)) { + $choices['group'] = get_string('group'); + } + + return array($choices, $allowed->groups); } /** @@ -1698,7 +2932,44 @@ function calendar_get_eventtype_choices($courseid) { * @return int The insert ID, if any. */ function calendar_add_subscription($sub) { - return \core_calendar\api::add_subscription($sub); + global $DB, $USER, $SITE; + + if ($sub->eventtype === 'site') { + $sub->courseid = $SITE->id; + } else if ($sub->eventtype === 'group' || $sub->eventtype === 'course') { + $sub->courseid = $sub->course; + } else { + // User events. + $sub->courseid = 0; + } + $sub->userid = $USER->id; + + // File subscriptions never update. + if (empty($sub->url)) { + $sub->pollinterval = 0; + } + + if (!empty($sub->name)) { + if (empty($sub->id)) { + $id = $DB->insert_record('event_subscriptions', $sub); + // We cannot cache the data here because $sub is not complete. + $sub->id = $id; + // Trigger event, calendar subscription added. + $eventparams = array('objectid' => $sub->id, + 'context' => calendar_get_calendar_context($sub), + 'other' => array('eventtype' => $sub->eventtype, 'courseid' => $sub->courseid) + ); + $event = \core\event\calendar_subscription_created::create($eventparams); + $event->trigger(); + return $id; + } else { + // Why are we doing an update here? + calendar_update_subscription($sub); + return $sub->id; + } + } else { + print_error('errorbadsubscription', 'importcalendar'); + } } /** @@ -1712,7 +2983,99 @@ function calendar_add_subscription($sub) { * @return int Code: CALENDAR_IMPORT_EVENT_UPDATED = updated, CALENDAR_IMPORT_EVENT_INSERTED = inserted, 0 = error */ function calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timezone='UTC') { - return \core_calendar\api::add_icalendar_event($event, $courseid, $subscriptionid, $timezone); + global $DB; + + // Probably an unsupported X-MICROSOFT-CDO-BUSYSTATUS event. + if (empty($event->properties['SUMMARY'])) { + return 0; + } + + $name = $event->properties['SUMMARY'][0]->value; + $name = str_replace('\n', '
', $name); + $name = str_replace('\\', '', $name); + $name = preg_replace('/\s+/u', ' ', $name); + + $eventrecord = new \stdClass; + $eventrecord->name = clean_param($name, PARAM_NOTAGS); + + if (empty($event->properties['DESCRIPTION'][0]->value)) { + $description = ''; + } else { + $description = $event->properties['DESCRIPTION'][0]->value; + $description = clean_param($description, PARAM_NOTAGS); + $description = str_replace('\n', '
', $description); + $description = str_replace('\\', '', $description); + $description = preg_replace('/\s+/u', ' ', $description); + } + $eventrecord->description = $description; + + // Probably a repeating event with RRULE etc. TODO: skip for now. + if (empty($event->properties['DTSTART'][0]->value)) { + return 0; + } + + if (isset($event->properties['DTSTART'][0]->parameters['TZID'])) { + $tz = $event->properties['DTSTART'][0]->parameters['TZID']; + } else { + $tz = $timezone; + } + $tz = \core_date::normalise_timezone($tz); + $eventrecord->timestart = strtotime($event->properties['DTSTART'][0]->value . ' ' . $tz); + if (empty($event->properties['DTEND'])) { + $eventrecord->timeduration = 0; // No duration if no end time specified. + } else { + if (isset($event->properties['DTEND'][0]->parameters['TZID'])) { + $endtz = $event->properties['DTEND'][0]->parameters['TZID']; + } else { + $endtz = $timezone; + } + $endtz = \core_date::normalise_timezone($endtz); + $eventrecord->timeduration = strtotime($event->properties['DTEND'][0]->value . ' ' . $endtz) - $eventrecord->timestart; + } + + // Check to see if it should be treated as an all day event. + if ($eventrecord->timeduration == DAYSECS) { + // Check to see if the event started at Midnight on the imported calendar. + date_default_timezone_set($timezone); + if (date('H:i:s', $eventrecord->timestart) === "00:00:00") { + // This event should be an all day event. + $eventrecord->timeduration = 0; + } + \core_date::set_default_server_timezone(); + } + + $eventrecord->uuid = $event->properties['UID'][0]->value; + $eventrecord->timemodified = time(); + + // Add the iCal subscription details if required. + // We should never do anything with an event without a subscription reference. + $sub = calendar_get_subscription($subscriptionid); + $eventrecord->subscriptionid = $subscriptionid; + $eventrecord->userid = $sub->userid; + $eventrecord->groupid = $sub->groupid; + $eventrecord->courseid = $sub->courseid; + $eventrecord->eventtype = $sub->eventtype; + + if ($updaterecord = $DB->get_record('event', array('uuid' => $eventrecord->uuid, + 'subscriptionid' => $eventrecord->subscriptionid))) { + $eventrecord->id = $updaterecord->id; + $return = CALENDAR_IMPORT_EVENT_UPDATED; // Update. + } else { + $return = CALENDAR_IMPORT_EVENT_INSERTED; // Insert. + } + if ($createdevent = \calendar_event::create($eventrecord, false)) { + if (!empty($event->properties['RRULE'])) { + // Repeating events. + date_default_timezone_set($tz); // Change time zone to parse all events. + $rrule = new rrule_manager($event->properties['RRULE'][0]->value); + $rrule->parse_rrule(); + $rrule->create_events($createdevent); + \core_date::set_default_server_timezone(); // Change time zone back to what it was. + } + return $return; + } else { + return 0; + } } /** @@ -1725,7 +3088,30 @@ function calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timez * @return string A log of the import progress, including errors */ function calendar_process_subscription_row($subscriptionid, $pollinterval, $action) { - return \core_calendar\api::process_subscription_row($subscriptionid, $pollinterval, $action); + // Fetch the subscription from the database making sure it exists. + $sub = calendar_get_subscription($subscriptionid); + + // Update or remove the subscription, based on action. + switch ($action) { + case CALENDAR_SUBSCRIPTION_UPDATE: + // Skip updating file subscriptions. + if (empty($sub->url)) { + break; + } + $sub->pollinterval = $pollinterval; + calendar_update_subscription($sub); + + // Update the events. + return "

" . get_string('subscriptionupdated', 'calendar', $sub->name) . "

" . + calendar_update_subscription_events($subscriptionid); + case CALENDAR_SUBSCRIPTION_REMOVE: + calendar_delete_subscription($subscriptionid); + return get_string('subscriptionremoved', 'calendar', $sub->name); + break; + default: + break; + } + return ''; } /** @@ -1734,7 +3120,24 @@ function calendar_process_subscription_row($subscriptionid, $pollinterval, $acti * @param int|stdClass $subscription subscription or it's id, which needs to be deleted. */ function calendar_delete_subscription($subscription) { - \core_calendar\api::delete_subscription($subscription); + global $DB; + + if (!is_object($subscription)) { + $subscription = $DB->get_record('event_subscriptions', array('id' => $subscription), '*', MUST_EXIST); + } + + // Delete subscription and related events. + $DB->delete_records('event', array('subscriptionid' => $subscription->id)); + $DB->delete_records('event_subscriptions', array('id' => $subscription->id)); + \cache_helper::invalidate_by_definition('core', 'calendar_subscriptions', array(), array($subscription->id)); + + // Trigger event, calendar subscription deleted. + $eventparams = array('objectid' => $subscription->id, + 'context' => calendar_get_calendar_context($subscription), + 'other' => array('courseid' => $subscription->courseid) + ); + $event = \core\event\calendar_subscription_deleted::create($eventparams); + $event->trigger(); } /** @@ -1744,7 +3147,23 @@ function calendar_delete_subscription($subscription) { * @return iCalendar The iCalendar object */ function calendar_get_icalendar($url) { - return \core_calendar\api::get_icalendar($url); + global $CFG; + + require_once($CFG->libdir . '/filelib.php'); + + $curl = new \curl(); + $curl->setopt(array('CURLOPT_FOLLOWLOCATION' => 1, 'CURLOPT_MAXREDIRS' => 5)); + $calendar = $curl->get($url); + + // Http code validation should actually be the job of curl class. + if (!$calendar || $curl->info['http_code'] != 200 || !empty($curl->errorno)) { + throw new \moodle_exception('errorinvalidicalurl', 'calendar'); + } + + $ical = new \iCalendar(); + $ical->unserialize($calendar); + + return $ical; } /** @@ -1756,7 +3175,65 @@ function calendar_get_icalendar($url) { * @return string A log of the import progress, including errors. */ function calendar_import_icalendar_events($ical, $courseid, $subscriptionid = null) { - return \core_calendar\api::import_icalendar_events($ical, $courseid, $subscriptionid); + global $DB; + + $return = ''; + $eventcount = 0; + $updatecount = 0; + + // Large calendars take a while... + if (!CLI_SCRIPT) { + \core_php_time_limit::raise(300); + } + + // Mark all events in a subscription with a zero timestamp. + if (!empty($subscriptionid)) { + $sql = "UPDATE {event} SET timemodified = :time WHERE subscriptionid = :id"; + $DB->execute($sql, array('time' => 0, 'id' => $subscriptionid)); + } + + // Grab the timezone from the iCalendar file to be used later. + if (isset($ical->properties['X-WR-TIMEZONE'][0]->value)) { + $timezone = $ical->properties['X-WR-TIMEZONE'][0]->value; + } else { + $timezone = 'UTC'; + } + + $return = ''; + foreach ($ical->components['VEVENT'] as $event) { + $res = calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timezone); + switch ($res) { + case CALENDAR_IMPORT_EVENT_UPDATED: + $updatecount++; + break; + case CALENDAR_IMPORT_EVENT_INSERTED: + $eventcount++; + break; + case 0: + $return .= '

' . get_string('erroraddingevent', 'calendar') . ': '; + if (empty($event->properties['SUMMARY'])) { + $return .= '(' . get_string('notitle', 'calendar') . ')'; + } else { + $return .= $event->properties['SUMMARY'][0]->value; + } + $return .= "

\n"; + break; + } + } + + $return .= "

" . get_string('eventsimported', 'calendar', $eventcount) . "

"; + $return .= "

" . get_string('eventsupdated', 'calendar', $updatecount) . "

"; + + // Delete remaining zero-marked events since they're not in remote calendar. + if (!empty($subscriptionid)) { + $deletecount = $DB->count_records('event', array('timemodified' => 0, 'subscriptionid' => $subscriptionid)); + if (!empty($deletecount)) { + $DB->delete_records('event', array('timemodified' => 0, 'subscriptionid' => $subscriptionid)); + $return .= "

" . get_string('eventsdeleted', 'calendar') . ": {$deletecount}

\n"; + } + } + + return $return; } /** @@ -1766,7 +3243,20 @@ function calendar_import_icalendar_events($ical, $courseid, $subscriptionid = nu * @return string A log of the import progress, including errors. */ function calendar_update_subscription_events($subscriptionid) { - return \core_calendar\api::update_subscription_events($subscriptionid); + $sub = calendar_get_subscription($subscriptionid); + + // Don't update a file subscription. + if (empty($sub->url)) { + return 'File subscription not updated.'; + } + + $ical = calendar_get_icalendar($sub->url); + $return = calendar_import_icalendar_events($ical, $sub->courseid, $subscriptionid); + $sub->lastupdated = time(); + + calendar_update_subscription($sub); + + return $return; } /** @@ -1777,7 +3267,29 @@ function calendar_update_subscription_events($subscriptionid) { * @since Moodle 2.5 */ function calendar_update_subscription($subscription) { - \core_calendar\api::update_subscription($subscription); + global $DB; + + if (is_array($subscription)) { + $subscription = (object)$subscription; + } + if (empty($subscription->id) || !$DB->record_exists('event_subscriptions', array('id' => $subscription->id))) { + throw new \coding_exception('Cannot update a subscription without a valid id'); + } + + $DB->update_record('event_subscriptions', $subscription); + + // Update cache. + $cache = \cache::make('core', 'calendar_subscriptions'); + $cache->set($subscription->id, $subscription); + + // Trigger event, calendar subscription updated. + $eventparams = array('userid' => $subscription->userid, + 'objectid' => $subscription->id, + 'context' => calendar_get_calendar_context($subscription), + 'other' => array('eventtype' => $subscription->eventtype, 'courseid' => $subscription->courseid) + ); + $event = \core\event\calendar_subscription_updated::create($eventparams); + $event->trigger(); } /** @@ -1787,7 +3299,39 @@ function calendar_update_subscription($subscription) { * @return bool true if current user can edit the subscription else false */ function calendar_can_edit_subscription($subscriptionorid) { - return \core_calendar\api::can_edit_subscription($subscriptionorid); + if (is_array($subscriptionorid)) { + $subscription = (object)$subscriptionorid; + } else if (is_object($subscriptionorid)) { + $subscription = $subscriptionorid; + } else { + $subscription = calendar_get_subscription($subscriptionorid); + } + + $allowed = new \stdClass; + $courseid = $subscription->courseid; + $groupid = $subscription->groupid; + + calendar_get_allowed_types($allowed, $courseid); + switch ($subscription->eventtype) { + case 'user': + return $allowed->user; + case 'course': + if (isset($allowed->courses[$courseid])) { + return $allowed->courses[$courseid]; + } else { + return false; + } + case 'site': + return $allowed->site; + case 'group': + if (isset($allowed->groups[$groupid])) { + return $allowed->groups[$groupid]; + } else { + return false; + } + default: + return false; + } } /** @@ -1798,7 +3342,15 @@ function calendar_can_edit_subscription($subscriptionorid) { * @return context instance */ function calendar_get_calendar_context($subscription) { - return \core_calendar\api::get_calendar_context($subscription); + // Determine context based on calendar type. + if ($subscription->eventtype === 'site') { + $context = \context_course::instance(SITEID); + } else if ($subscription->eventtype === 'group' || $subscription->eventtype === 'course') { + $context = \context_course::instance($subscription->courseid); + } else { + $context = \context_user::instance($subscription->userid); + } + return $context; } /** diff --git a/calendar/managesubscriptions.php b/calendar/managesubscriptions.php index 91dea50ed4f..3e4e0e98f69 100644 --- a/calendar/managesubscriptions.php +++ b/calendar/managesubscriptions.php @@ -49,10 +49,10 @@ if ($courseid != SITEID && !empty($courseid)) { $courses = array($course->id => $course); } else { $course = get_site(); - $courses = \core_calendar\api::get_default_courses(); + $courses = calendar_get_default_courses(); } require_course_login($course); -if (!\core_calendar\api::can_add_event_to_course($course)) { +if (!calendar_user_can_add_event($course)) { print_error('errorcannotimport', 'calendar'); } @@ -66,20 +66,20 @@ $importresults = ''; $formdata = $form->get_data(); if (!empty($formdata)) { require_sesskey(); // Must have sesskey for all actions. - $subscriptionid = \core_calendar\api::add_subscription($formdata); + $subscriptionid = calendar_add_subscription($formdata); if ($formdata->importfrom == CALENDAR_IMPORT_FROM_FILE) { // Blank the URL if it's a file import. $formdata->url = ''; $calendar = $form->get_file_content('importfile'); $ical = new iCalendar(); $ical->unserialize($calendar); - $importresults = \core_calendar\api::import_icalendar_events($ical, $courseid, $subscriptionid); + $importresults = calendar_import_icalendar_events($ical, $courseid, $subscriptionid); } else { try { - $importresults = \core_calendar\api::update_subscription_events($subscriptionid); + $importresults = calendar_update_subscription_events($subscriptionid); } catch (moodle_exception $e) { // Delete newly added subscription and show invalid url error. - \core_calendar\api::delete_subscription($subscriptionid); + calendar_delete_subscription($subscriptionid); print_error($e->errorcode, $e->module, $PAGE->url); } } @@ -88,9 +88,9 @@ if (!empty($formdata)) { } else if (!empty($subscriptionid)) { // The user is wanting to perform an action upon an existing subscription. require_sesskey(); // Must have sesskey for all actions. - if (\core_calendar\api::can_edit_subscription($subscriptionid)) { + if (calendar_can_edit_subscription($subscriptionid)) { try { - $importresults = \core_calendar\api::process_subscription_row($subscriptionid, $pollinterval, $action); + $importresults = calendar_process_subscription_row($subscriptionid, $pollinterval, $action); } catch (moodle_exception $e) { // If exception caught, then user should be redirected to page where he/she came from. print_error($e->errorcode, $e->module, $PAGE->url); @@ -117,7 +117,7 @@ echo $OUTPUT->header(); // Filter subscriptions which user can't edit. foreach($subscriptions as $subscription) { - if (!\core_calendar\api::can_edit_subscription($subscription)) { + if (!calendar_can_edit_subscription($subscription)) { unset($subscriptions[$subscription->id]); } } diff --git a/calendar/managesubscriptions_form.php b/calendar/managesubscriptions_form.php index ea2df718782..12ab3ac5b74 100644 --- a/calendar/managesubscriptions_form.php +++ b/calendar/managesubscriptions_form.php @@ -63,7 +63,7 @@ class calendar_addsubscription_form extends moodleform { $mform->setForceLtr('url'); // Poll interval - $choices = \core_calendar\api::get_poll_interval_choices(); + $choices = calendar_get_pollinterval_choices(); $mform->addElement('select', 'pollinterval', get_string('pollinterval', 'calendar'), $choices); $mform->setDefault('pollinterval', 604800); $mform->addHelpButton('pollinterval', 'pollinterval', 'calendar'); @@ -78,7 +78,7 @@ class calendar_addsubscription_form extends moodleform { $mform->disabledIf('importfile', 'importfrom', 'eq', CALENDAR_IMPORT_FROM_URL); // Eventtype: 0 = user, 1 = global, anything else = course ID. - list($choices, $groups) = \core_calendar\api::get_event_type_choices($courseid); + list($choices, $groups) = calendar_get_eventtype_choices($courseid); $mform->addElement('select', 'eventtype', get_string('eventkind', 'calendar'), $choices); $mform->addRule('eventtype', get_string('required'), 'required'); $mform->setType('eventtype', PARAM_ALPHA); diff --git a/calendar/renderer.php b/calendar/renderer.php index 3b228190dcf..ec209c34880 100644 --- a/calendar/renderer.php +++ b/calendar/renderer.php @@ -64,7 +64,7 @@ class core_calendar_renderer extends plugin_renderer_base { public function fake_block_filters($courseid, $day, $month, $year, $view, $courses) { $returnurl = $this->page->url; $returnurl->param('course', $courseid); - return html_writer::tag('div', \core_calendar\api::get_filter_controls($returnurl), + return html_writer::tag('div', calendar_filter_controls($returnurl), array('class' => 'calendar_filters filters')); } @@ -82,26 +82,26 @@ class core_calendar_renderer extends plugin_renderer_base { $date = $calendartype->timestamp_to_date_array($calendar->time); - $prevmonth = \core_calendar\api::get_prev_month($date['mon'], $date['year']); + $prevmonth = calendar_sub_month($date['mon'], $date['year']); $prevmonthtime = $calendartype->convert_to_gregorian($prevmonth[1], $prevmonth[0], 1); $prevmonthtime = make_timestamp($prevmonthtime['year'], $prevmonthtime['month'], $prevmonthtime['day'], $prevmonthtime['hour'], $prevmonthtime['minute']); - $nextmonth = \core_calendar\api::get_next_month($date['mon'], $date['year']); + $nextmonth = calendar_add_month($date['mon'], $date['year']); $nextmonthtime = $calendartype->convert_to_gregorian($nextmonth[1], $nextmonth[0], 1); $nextmonthtime = make_timestamp($nextmonthtime['year'], $nextmonthtime['month'], $nextmonthtime['day'], $nextmonthtime['hour'], $nextmonthtime['minute']); $content = html_writer::start_tag('div', array('class' => 'minicalendarblock')); - $content .= \core_calendar\api::get_mini_calendar($calendar->courses, $calendar->groups, $calendar->users, + $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $prevmonthtime); $content .= html_writer::end_tag('div'); $content .= html_writer::start_tag('div', array('class' => 'minicalendarblock')); - $content .= \core_calendar\api::get_mini_calendar($calendar->courses, $calendar->groups, $calendar->users, + $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $calendar->time); $content .= html_writer::end_tag('div'); $content .= html_writer::start_tag('div', array('class' => 'minicalendarblock')); - $content .= \core_calendar\api::get_mini_calendar($calendar->courses, $calendar->groups, $calendar->users, + $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $nextmonthtime); $content .= html_writer::end_tag('div'); return $content; @@ -168,17 +168,17 @@ class core_calendar_renderer extends plugin_renderer_base { $returnurl = $this->page->url; } - $events = \core_calendar\api::get_upcoming($calendar->courses, $calendar->groups, $calendar->users, + $events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, 1, 100, $calendar->timestamp_today()); $output = html_writer::start_tag('div', array('class'=>'header')); $output .= $this->course_filter_selector($returnurl, get_string('dayviewfor', 'calendar')); - if (\core_calendar\api::can_add_event_to_course($calendar->course)) { + if (calendar_user_can_add_event($calendar->course)) { $output .= $this->add_event_button($calendar->course->id, 0, 0, 0, $calendar->time); } $output .= html_writer::end_tag('div'); // Controls - $output .= html_writer::tag('div', \core_calendar\api::get_top_controls('day', array('id' => $calendar->courseid, + $output .= html_writer::tag('div', calendar_top_controls('day', array('id' => $calendar->courseid, 'time' => $calendar->time)), array('class' => 'controls')); if (empty($events)) { @@ -192,7 +192,7 @@ class core_calendar_renderer extends plugin_renderer_base { $event = new calendar_event($event); $event->calendarcourseid = $calendar->courseid; if ($event->timestart >= $calendar->timestamp_today() && $event->timestart <= $calendar->timestamp_tomorrow()-1) { // Print it now - $event->time = \core_calendar\api::get_format_event_time($event, time(), null, false, + $event->time = calendar_format_event_time($event, time(), null, false, $calendar->timestamp_today()); $output .= $this->event($event); } else { // Save this for later @@ -205,7 +205,7 @@ class core_calendar_renderer extends plugin_renderer_base { $output .= html_writer::span(get_string('spanningevents', 'calendar'), 'calendar-information calendar-span-multiple-days'); foreach ($underway as $event) { - $event->time = \core_calendar\api::get_format_event_time($event, time(), null, false, + $event->time = calendar_format_event_time($event, time(), null, false, $calendar->timestamp_today()); $output .= $this->event($event); } @@ -227,12 +227,12 @@ class core_calendar_renderer extends plugin_renderer_base { public function event(calendar_event $event, $showactions=true) { global $CFG; - $event = \core_calendar\api::add_event_metadata($event); + $event = calendar_add_event_metadata($event); $context = $event->context; $output = ''; $output .= $this->output->box_start('card-header clearfix'); - if (\core_calendar\api::can_edit_event($event) && $showactions) { + if (calendar_edit_event_allowed($event) && $showactions) { if (empty($event->cmid)) { $editlink = new moodle_url(CALENDAR_URL.'event.php', array('action' => 'edit', 'id' => $event->id)); $deletelink = new moodle_url(CALENDAR_URL.'delete.php', array('id' => $event->id)); @@ -289,7 +289,7 @@ class core_calendar_renderer extends plugin_renderer_base { $output .= html_writer::tag('span', $event->time, array('class' => 'date pull-xs-right m-r-1')); } else { $attrs = array('class' => 'date pull-xs-right m-r-1'); - $output .= html_writer::tag('span', \core_calendar\api::get_time_representation($event->timestart), $attrs); + $output .= html_writer::tag('span', calendar_time_representation($event->timestart), $attrs); } if (!empty($event->courselink)) { $output .= html_writer::tag('div', $event->courselink, array('class' => 'course')); @@ -352,13 +352,13 @@ class core_calendar_renderer extends plugin_renderer_base { // Get the starting week day for this month. $startwday = dayofweek(1, $date['mon'], $date['year']); // Get the days in a week. - $daynames = \core_calendar\api::get_days(); + $daynames = calendar_get_days(); // Store the number of days in a week. $numberofdaysinweek = $calendartype->get_num_weekdays(); - $display->minwday = \core_calendar\api::get_starting_weekday(); + $display->minwday = calendar_get_starting_weekday(); $display->maxwday = $display->minwday + ($numberofdaysinweek - 1); - $display->maxdays = \core_calendar\api::get_days_in_month($date['mon'], $date['year']); + $display->maxdays = calendar_days_in_month($date['mon'], $date['year']); // These are used for DB queries, so we want unixtime, so we need to use Gregorian dates. $display->tstart = make_timestamp($gy, $gm, $gd, $gh, $gmin, 0); @@ -371,7 +371,7 @@ class core_calendar_renderer extends plugin_renderer_base { } // Get events from database - $events = \core_calendar\api::get_events($display->tstart, $display->tend, $calendar->users, $calendar->groups, + $events = calendar_get_events($display->tstart, $display->tend, $calendar->users, $calendar->groups, $calendar->courses); if (!empty($events)) { foreach($events as $eventid => $event) { @@ -386,17 +386,17 @@ class core_calendar_renderer extends plugin_renderer_base { } // Extract information: events vs. time - \core_calendar\api::get_events_by_day($events, $date['mon'], $date['year'], $eventsbyday, $durationbyday, + calendar_events_by_day($events, $date['mon'], $date['year'], $eventsbyday, $durationbyday, $typesbyday, $calendar->courses); $output = html_writer::start_tag('div', array('class'=>'header')); $output .= $this->course_filter_selector($returnurl, get_string('detailedmonthviewfor', 'calendar')); - if (\core_calendar\api::can_add_event_to_course($calendar->course)) { + if (calendar_user_can_add_event($calendar->course)) { $output .= $this->add_event_button($calendar->course->id, 0, 0, 0, $calendar->time); } $output .= html_writer::end_tag('div', array('class'=>'header')); // Controls - $output .= html_writer::tag('div', \core_calendar\api::get_top_controls('month', array('id' => $calendar->courseid, + $output .= html_writer::tag('div', calendar_top_controls('month', array('id' => $calendar->courseid, 'time' => $calendar->time)), array('class' => 'controls')); $table = new html_table(); @@ -443,7 +443,7 @@ class core_calendar_renderer extends plugin_renderer_base { // Reset vars $cell = new html_table_cell(); - $dayhref = \core_calendar\api::get_link_href(new moodle_url(CALENDAR_URL . 'view.php', + $dayhref = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', array('view' => 'day', 'course' => $calendar->courseid)), 0, 0, 0, $daytime); $cellclasses = array(); @@ -539,12 +539,12 @@ class core_calendar_renderer extends plugin_renderer_base { $returnurl = $this->page->url; } - $events = \core_calendar\api::get_upcoming($calendar->courses, $calendar->groups, $calendar->users, + $events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, $futuredays, $maxevents); $output = html_writer::start_tag('div', array('class'=>'header')); $output .= $this->course_filter_selector($returnurl, get_string('upcomingeventsfor', 'calendar')); - if (\core_calendar\api::can_add_event_to_course($calendar->course)) { + if (calendar_user_can_add_event($calendar->course)) { $output .= $this->add_event_button($calendar->course->id); } $output .= html_writer::end_tag('div'); @@ -686,7 +686,7 @@ class core_calendar_renderer extends plugin_renderer_base { // Assemble pollinterval control. $html .= html_writer::start_tag('div', array('style' => 'float:left;')); $html .= html_writer::start_tag('select', array('name' => 'pollinterval', 'class' => 'custom-select')); - foreach (\core_calendar\api::get_poll_interval_choices() as $k => $v) { + foreach (calendar_get_pollinterval_choices() as $k => $v) { $attributes = array(); if ($k == $subscription->pollinterval) { $attributes['selected'] = 'selected'; diff --git a/calendar/set.php b/calendar/set.php index a25853d4837..c69de934a1a 100644 --- a/calendar/set.php +++ b/calendar/set.php @@ -44,16 +44,16 @@ $PAGE->set_context(context_system::instance()); switch($var) { case 'showgroups': - \core_calendar\api::set_event_type_display(CALENDAR_EVENT_GROUP); + calendar_set_event_type_display(CALENDAR_EVENT_GROUP); break; case 'showcourses': - \core_calendar\api::set_event_type_display(CALENDAR_EVENT_COURSE); + calendar_set_event_type_display(CALENDAR_EVENT_COURSE); break; case 'showglobal': - \core_calendar\api::set_event_type_display(CALENDAR_EVENT_GLOBAL); + calendar_set_event_type_display(CALENDAR_EVENT_GLOBAL); break; case 'showuser': - \core_calendar\api::set_event_type_display(CALENDAR_EVENT_USER); + calendar_set_event_type_display(CALENDAR_EVENT_USER); break; } diff --git a/calendar/tests/api_test.php b/calendar/tests/api_test.php index 7b2eaff0a2a..aaa36312360 100644 --- a/calendar/tests/api_test.php +++ b/calendar/tests/api_test.php @@ -44,357 +44,6 @@ class core_calendar_api_testcase extends advanced_testcase { $this->resetAfterTest(); } - public function test_get_course_cached() { - // Setup some test courses. - $course1 = $this->getDataGenerator()->create_course(); - $course2 = $this->getDataGenerator()->create_course(); - $course3 = $this->getDataGenerator()->create_course(); - - // Load courses into cache. - $coursecache = null; - \core_calendar\api::get_course_cached($coursecache, $course1->id); - \core_calendar\api::get_course_cached($coursecache, $course2->id); - \core_calendar\api::get_course_cached($coursecache, $course3->id); - - // Verify the cache. - $this->assertArrayHasKey($course1->id, $coursecache); - $cachedcourse1 = $coursecache[$course1->id]; - $this->assertEquals($course1->id, $cachedcourse1->id); - $this->assertEquals($course1->shortname, $cachedcourse1->shortname); - $this->assertEquals($course1->fullname, $cachedcourse1->fullname); - - $this->assertArrayHasKey($course2->id, $coursecache); - $cachedcourse2 = $coursecache[$course2->id]; - $this->assertEquals($course2->id, $cachedcourse2->id); - $this->assertEquals($course2->shortname, $cachedcourse2->shortname); - $this->assertEquals($course2->fullname, $cachedcourse2->fullname); - - $this->assertArrayHasKey($course3->id, $coursecache); - $cachedcourse3 = $coursecache[$course3->id]; - $this->assertEquals($course3->id, $cachedcourse3->id); - $this->assertEquals($course3->shortname, $cachedcourse3->shortname); - $this->assertEquals($course3->fullname, $cachedcourse3->fullname); - } - - /** - * Test that the get_events() function only returns activity events that are enabled. - */ - public function test_get_events_with_disabled_module() { - global $DB; - $this->setAdminUser(); - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); - $assigninstance = $assigngenerator->create_instance(['course' => $course->id]); - $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson'); - $lessoninstance = $lessongenerator->create_instance(['course' => $course->id]); - $student = $generator->create_user(); - $generator->enrol_user($student->id, $course->id, 'student'); - $this->setUser($student); - $events = [ - [ - 'name' => 'Start of assignment', - 'description' => '', - 'format' => 1, - 'courseid' => $course->id, - 'groupid' => 0, - 'userid' => 2, - 'modulename' => 'assign', - 'instance' => $assigninstance->id, - 'eventtype' => 'due', - 'timestart' => time(), - 'timeduration' => 86400, - 'visible' => 1 - ], [ - 'name' => 'Start of lesson', - 'description' => '', - 'format' => 1, - 'courseid' => $course->id, - 'groupid' => 0, - 'userid' => 2, - 'modulename' => 'lesson', - 'instance' => $lessoninstance->id, - 'eventtype' => 'end', - 'timestart' => time(), - 'timeduration' => 86400, - 'visible' => 1 - ] - ]; - foreach ($events as $event) { - calendar_event::create($event, false); - } - $timestart = time() - 60; - $timeend = time() + 60; - // Get all events. - $events = \core_calendar\api::get_events($timestart, $timeend, true, 0, true); - $this->assertCount(2, $events); - // Disable the lesson module. - $modulerecord = $DB->get_record('modules', ['name' => 'lesson']); - $modulerecord->visible = 0; - $DB->update_record('modules', $modulerecord); - // Check that we only return the assign event. - $events = \core_calendar\api::get_events($timestart, $timeend, true, 0, true); - $this->assertCount(1, $events); - $event = reset($events); - $this->assertEquals('assign', $event->modulename); - } - - /** - * Test for calendar_get_events() when there are user and group overrides. - */ - public function test_calendar_get_events_with_overrides() { - global $DB; - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); - if (!isset($params['course'])) { - $params['course'] = $course->id; - } - $instance = $plugingenerator->create_instance($params); - // Create users. - $useroverridestudent = $generator->create_user(); - $group1student = $generator->create_user(); - $group2student = $generator->create_user(); - $group12student = $generator->create_user(); - $nogroupstudent = $generator->create_user(); - // Enrol users. - $generator->enrol_user($useroverridestudent->id, $course->id, 'student'); - $generator->enrol_user($group1student->id, $course->id, 'student'); - $generator->enrol_user($group2student->id, $course->id, 'student'); - $generator->enrol_user($group12student->id, $course->id, 'student'); - $generator->enrol_user($nogroupstudent->id, $course->id, 'student'); - // Create groups. - $group1 = $generator->create_group(['courseid' => $course->id]); - $group2 = $generator->create_group(['courseid' => $course->id]); - // Add members to groups. - $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group1student->id]); - $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group2student->id]); - $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group12student->id]); - $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group12student->id]); - $now = time(); - // Events with the same module name, instance and event type. - $events = [ - [ - 'name' => 'Assignment 1 due date', - 'description' => '', - 'format' => 0, - 'courseid' => $course->id, - 'groupid' => 0, - 'userid' => 2, - 'modulename' => 'assign', - 'instance' => $instance->id, - 'eventtype' => 'due', - 'timestart' => $now, - 'timeduration' => 0, - 'visible' => 1 - ], [ - 'name' => 'Assignment 1 due date - User override', - 'description' => '', - 'format' => 1, - 'courseid' => 0, - 'groupid' => 0, - 'userid' => $useroverridestudent->id, - 'modulename' => 'assign', - 'instance' => $instance->id, - 'eventtype' => 'due', - 'timestart' => $now + 86400, - 'timeduration' => 0, - 'visible' => 1, - 'priority' => CALENDAR_EVENT_USER_OVERRIDE_PRIORITY - ], [ - 'name' => 'Assignment 1 due date - Group A override', - 'description' => '', - 'format' => 1, - 'courseid' => $course->id, - 'groupid' => $group1->id, - 'userid' => 2, - 'modulename' => 'assign', - 'instance' => $instance->id, - 'eventtype' => 'due', - 'timestart' => $now + (2 * 86400), - 'timeduration' => 0, - 'visible' => 1, - 'priority' => 1, - ], [ - 'name' => 'Assignment 1 due date - Group B override', - 'description' => '', - 'format' => 1, - 'courseid' => $course->id, - 'groupid' => $group2->id, - 'userid' => 2, - 'modulename' => 'assign', - 'instance' => $instance->id, - 'eventtype' => 'due', - 'timestart' => $now + (3 * 86400), - 'timeduration' => 0, - 'visible' => 1, - 'priority' => 2, - ], - ]; - foreach ($events as $event) { - calendar_event::create($event, false); - } - $timestart = $now - 100; - $timeend = $now + (3 * 86400); - $groups = [$group1->id, $group2->id]; - // Get user override events. - $this->setUser($useroverridestudent); - $events = \core_calendar\api::get_events($timestart, $timeend, $useroverridestudent->id, $groups, $course->id); - $this->assertCount(1, $events); - $event = reset($events); - $this->assertEquals('Assignment 1 due date - User override', $event->name); - // Get event for user with override but with the timestart and timeend parameters only covering the original event. - $events = \core_calendar\api::get_events($timestart, $now, $useroverridestudent->id, $groups, $course->id); - $this->assertCount(0, $events); - // Get events for user that does not belong to any group and has no user override events. - $this->setUser($nogroupstudent); - $events = \core_calendar\api::get_events($timestart, $timeend, $nogroupstudent->id, $groups, $course->id); - $this->assertCount(1, $events); - $event = reset($events); - $this->assertEquals('Assignment 1 due date', $event->name); - // Get events for user that belongs to groups A and B and has no user override events. - $this->setUser($group12student); - $events = \core_calendar\api::get_events($timestart, $timeend, $group12student->id, $groups, $course->id); - $this->assertCount(1, $events); - $event = reset($events); - $this->assertEquals('Assignment 1 due date - Group B override', $event->name); - // Get events for user that belongs to group A and has no user override events. - $this->setUser($group1student); - $events = \core_calendar\api::get_events($timestart, $timeend, $group1student->id, $groups, $course->id); - $this->assertCount(1, $events); - $event = reset($events); - $this->assertEquals('Assignment 1 due date - Group A override', $event->name); - // Add repeating events. - $repeatingevents = [ - [ - 'name' => 'Repeating site event', - 'description' => '', - 'format' => 1, - 'courseid' => SITEID, - 'groupid' => 0, - 'userid' => 2, - 'repeatid' => $event->id, - 'modulename' => '0', - 'instance' => 0, - 'eventtype' => 'site', - 'timestart' => $now + 86400, - 'timeduration' => 0, - 'visible' => 1, - ], - [ - 'name' => 'Repeating site event', - 'description' => '', - 'format' => 1, - 'courseid' => SITEID, - 'groupid' => 0, - 'userid' => 2, - 'repeatid' => $event->id, - 'modulename' => '0', - 'instance' => 0, - 'eventtype' => 'site', - 'timestart' => $now + (2 * 86400), - 'timeduration' => 0, - 'visible' => 1, - ], - ]; - foreach ($repeatingevents as $event) { - calendar_event::create($event, false); - } - // Make sure repeating events are not filtered out. - $events = \core_calendar\api::get_events($timestart, $timeend, true, true, true); - $this->assertCount(3, $events); - } - - /** - * Test the update_subscription() function. - */ - public function test_update_subscription() { - $this->resetAfterTest(true); - - $subscription = new stdClass(); - $subscription->eventtype = 'site'; - $subscription->name = 'test'; - $id = \core_calendar\api::add_subscription($subscription); - - $subscription = \core_calendar\api::get_subscription($id); - $subscription->name = 'awesome'; - \core_calendar\api::update_subscription($subscription); - $sub = \core_calendar\api::get_subscription($id); - $this->assertEquals($subscription->name, $sub->name); - - $subscription = \core_calendar\api::get_subscription($id); - $subscription->name = 'awesome2'; - $subscription->pollinterval = 604800; - \core_calendar\api::update_subscription($subscription); - $sub = \core_calendar\api::get_subscription($id); - $this->assertEquals($subscription->name, $sub->name); - $this->assertEquals($subscription->pollinterval, $sub->pollinterval); - - $subscription = new stdClass(); - $subscription->name = 'awesome4'; - $this->expectException('coding_exception'); - \core_calendar\api::update_subscription($subscription); - } - - public function test_add_subscription() { - global $DB, $CFG; - - require_once($CFG->dirroot . '/lib/bennu/bennu.inc.php'); - - $this->resetAfterTest(true); - - // Test for Microsoft Outlook 2010. - $subscription = new stdClass(); - $subscription->name = 'Microsoft Outlook 2010'; - $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; - $subscription->eventtype = 'site'; - $id = \core_calendar\api::add_subscription($subscription); - - $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/ms_outlook_2010.ics'); - $ical = new iCalendar(); - $ical->unserialize($calendar); - $this->assertEquals($ical->parser_errors, array()); - - $sub = \core_calendar\api::get_subscription($id); - \core_calendar\api::import_icalendar_events($ical, $sub->courseid, $sub->id); - $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); - $this->assertEquals($count, 1); - - // Test for OSX Yosemite. - $subscription = new stdClass(); - $subscription->name = 'OSX Yosemite'; - $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; - $subscription->eventtype = 'site'; - $id = \core_calendar\api::add_subscription($subscription); - - $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/osx_yosemite.ics'); - $ical = new iCalendar(); - $ical->unserialize($calendar); - $this->assertEquals($ical->parser_errors, array()); - - $sub = \core_calendar\api::get_subscription($id); - \core_calendar\api::import_icalendar_events($ical, $sub->courseid, $sub->id); - $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); - $this->assertEquals($count, 1); - - // Test for Google Gmail. - $subscription = new stdClass(); - $subscription->name = 'Google Gmail'; - $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; - $subscription->eventtype = 'site'; - $id = \core_calendar\api::add_subscription($subscription); - - $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/google_gmail.ics'); - $ical = new iCalendar(); - $ical->unserialize($calendar); - $this->assertEquals($ical->parser_errors, array()); - - $sub = \core_calendar\api::get_subscription($id); - \core_calendar\api::import_icalendar_events($ical, $sub->courseid, $sub->id); - $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); - $this->assertEquals($count, 1); - } - /** * Requesting calendar events from a given time should return all events with a sort * time at or after the requested time. All events prior to that time should not diff --git a/calendar/tests/calendartype_test.php b/calendar/tests/calendartype_test.php index f9fd7e52558..5d9af035811 100644 --- a/calendar/tests/calendartype_test.php +++ b/calendar/tests/calendartype_test.php @@ -195,11 +195,11 @@ class core_calendar_type_testcase extends advanced_testcase { userdate($this->user->timecreated)); // Test the calendar/lib.php functions. - $this->assertEquals($calendar->get_weekdays(), \core_calendar\api::get_days()); - $this->assertEquals($calendar->get_starting_weekday(), \core_calendar\api::get_starting_weekday()); - $this->assertEquals($calendar->get_num_days_in_month('1986', '9'), \core_calendar\api::get_days_in_month('9', '1986')); - $this->assertEquals($calendar->get_next_month('1986', '9'), \core_calendar\api::get_next_month('9', '1986')); - $this->assertEquals($calendar->get_prev_month('1986', '9'), \core_calendar\api::get_prev_month('9', '1986')); + $this->assertEquals($calendar->get_weekdays(), calendar_get_days()); + $this->assertEquals($calendar->get_starting_weekday(), calendar_get_starting_weekday()); + $this->assertEquals($calendar->get_num_days_in_month('1986', '9'), calendar_days_in_month('9', '1986')); + $this->assertEquals($calendar->get_next_month('1986', '9'), calendar_add_month('9', '1986')); + $this->assertEquals($calendar->get_prev_month('1986', '9'), calendar_sub_month('9', '1986')); // Test the lib/moodle.php functions. $this->assertEquals($calendar->get_num_days_in_month('1986', '9'), days_in_month('9', '1986')); diff --git a/calendar/tests/events_test.php b/calendar/tests/events_test.php index 3331cbd9b6d..6f78848a059 100644 --- a/calendar/tests/events_test.php +++ b/calendar/tests/events_test.php @@ -438,7 +438,7 @@ class core_calendar_events_testcase extends advanced_testcase { // Trigger and capture the event. $sink = $this->redirectEvents(); - $id = \core_calendar\api::add_subscription($subscription); + $id = calendar_add_subscription($subscription); $events = $sink->get_events(); $event = reset($events); @@ -465,13 +465,13 @@ class core_calendar_events_testcase extends advanced_testcase { $subscription->eventtype = 'site'; $subscription->name = 'test'; $subscription->courseid = $this->course->id; - $subscription->id = \core_calendar\api::add_subscription($subscription); + $subscription->id = calendar_add_subscription($subscription); // Now edit it. $subscription->name = 'awesome'; // Trigger and capture the event. $sink = $this->redirectEvents(); - \core_calendar\api::update_subscription($subscription); + calendar_update_subscription($subscription); $events = $sink->get_events(); $event = reset($events); // Check that the event data is valid. @@ -497,11 +497,11 @@ class core_calendar_events_testcase extends advanced_testcase { $subscription->eventtype = 'site'; $subscription->name = 'test'; $subscription->courseid = $this->course->id; - $subscription->id = \core_calendar\api::add_subscription($subscription); + $subscription->id = calendar_add_subscription($subscription); // Trigger and capture the event. $sink = $this->redirectEvents(); - \core_calendar\api::delete_subscription($subscription); + calendar_delete_subscription($subscription); $events = $sink->get_events(); $event = reset($events); // Check that the event data is valid. diff --git a/calendar/tests/lib_test.php b/calendar/tests/lib_test.php new file mode 100644 index 00000000000..797dc891c42 --- /dev/null +++ b/calendar/tests/lib_test.php @@ -0,0 +1,395 @@ +. + +/** + * Contains the class containing unit tests for the calendar lib. + * + * @package core_calendar + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once(__DIR__ . '/helpers.php'); + +/** + * Class contaning unit tests for the calendar lib. + * + * @package core_calendar + * @copyright 2017 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_calendar_lib_testcase extends advanced_testcase { + + /** + * Tests set up + */ + protected function setUp() { + $this->resetAfterTest(); + } + + /** + * Test that the get_events() function only returns activity events that are enabled. + */ + public function test_get_events_with_disabled_module() { + global $DB; + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); + $assigninstance = $assigngenerator->create_instance(['course' => $course->id]); + $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson'); + $lessoninstance = $lessongenerator->create_instance(['course' => $course->id]); + $student = $generator->create_user(); + $generator->enrol_user($student->id, $course->id, 'student'); + $this->setUser($student); + $events = [ + [ + 'name' => 'Start of assignment', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => 0, + 'userid' => 2, + 'modulename' => 'assign', + 'instance' => $assigninstance->id, + 'eventtype' => 'due', + 'timestart' => time(), + 'timeduration' => 86400, + 'visible' => 1 + ], [ + 'name' => 'Start of lesson', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => 0, + 'userid' => 2, + 'modulename' => 'lesson', + 'instance' => $lessoninstance->id, + 'eventtype' => 'end', + 'timestart' => time(), + 'timeduration' => 86400, + 'visible' => 1 + ] + ]; + foreach ($events as $event) { + calendar_event::create($event, false); + } + $timestart = time() - 60; + $timeend = time() + 60; + // Get all events. + $events = calendar_get_events($timestart, $timeend, true, 0, true); + $this->assertCount(2, $events); + // Disable the lesson module. + $modulerecord = $DB->get_record('modules', ['name' => 'lesson']); + $modulerecord->visible = 0; + $DB->update_record('modules', $modulerecord); + // Check that we only return the assign event. + $events = calendar_get_events($timestart, $timeend, true, 0, true); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertEquals('assign', $event->modulename); + } + + /** + * Test for calendar_get_events() when there are user and group overrides. + */ + public function test_calendar_get_events_with_overrides() { + global $DB; + $generator = $this->getDataGenerator(); + $course = $generator->create_course(); + $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); + if (!isset($params['course'])) { + $params['course'] = $course->id; + } + $instance = $plugingenerator->create_instance($params); + // Create users. + $useroverridestudent = $generator->create_user(); + $group1student = $generator->create_user(); + $group2student = $generator->create_user(); + $group12student = $generator->create_user(); + $nogroupstudent = $generator->create_user(); + // Enrol users. + $generator->enrol_user($useroverridestudent->id, $course->id, 'student'); + $generator->enrol_user($group1student->id, $course->id, 'student'); + $generator->enrol_user($group2student->id, $course->id, 'student'); + $generator->enrol_user($group12student->id, $course->id, 'student'); + $generator->enrol_user($nogroupstudent->id, $course->id, 'student'); + // Create groups. + $group1 = $generator->create_group(['courseid' => $course->id]); + $group2 = $generator->create_group(['courseid' => $course->id]); + // Add members to groups. + $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group1student->id]); + $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group2student->id]); + $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group12student->id]); + $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group12student->id]); + $now = time(); + // Events with the same module name, instance and event type. + $events = [ + [ + 'name' => 'Assignment 1 due date', + 'description' => '', + 'format' => 0, + 'courseid' => $course->id, + 'groupid' => 0, + 'userid' => 2, + 'modulename' => 'assign', + 'instance' => $instance->id, + 'eventtype' => 'due', + 'timestart' => $now, + 'timeduration' => 0, + 'visible' => 1 + ], [ + 'name' => 'Assignment 1 due date - User override', + 'description' => '', + 'format' => 1, + 'courseid' => 0, + 'groupid' => 0, + 'userid' => $useroverridestudent->id, + 'modulename' => 'assign', + 'instance' => $instance->id, + 'eventtype' => 'due', + 'timestart' => $now + 86400, + 'timeduration' => 0, + 'visible' => 1, + 'priority' => CALENDAR_EVENT_USER_OVERRIDE_PRIORITY + ], [ + 'name' => 'Assignment 1 due date - Group A override', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => $group1->id, + 'userid' => 2, + 'modulename' => 'assign', + 'instance' => $instance->id, + 'eventtype' => 'due', + 'timestart' => $now + (2 * 86400), + 'timeduration' => 0, + 'visible' => 1, + 'priority' => 1, + ], [ + 'name' => 'Assignment 1 due date - Group B override', + 'description' => '', + 'format' => 1, + 'courseid' => $course->id, + 'groupid' => $group2->id, + 'userid' => 2, + 'modulename' => 'assign', + 'instance' => $instance->id, + 'eventtype' => 'due', + 'timestart' => $now + (3 * 86400), + 'timeduration' => 0, + 'visible' => 1, + 'priority' => 2, + ], + ]; + foreach ($events as $event) { + calendar_event::create($event, false); + } + $timestart = $now - 100; + $timeend = $now + (3 * 86400); + $groups = [$group1->id, $group2->id]; + // Get user override events. + $this->setUser($useroverridestudent); + $events = calendar_get_events($timestart, $timeend, $useroverridestudent->id, $groups, $course->id); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertEquals('Assignment 1 due date - User override', $event->name); + // Get event for user with override but with the timestart and timeend parameters only covering the original event. + $events = calendar_get_events($timestart, $now, $useroverridestudent->id, $groups, $course->id); + $this->assertCount(0, $events); + // Get events for user that does not belong to any group and has no user override events. + $this->setUser($nogroupstudent); + $events = calendar_get_events($timestart, $timeend, $nogroupstudent->id, $groups, $course->id); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertEquals('Assignment 1 due date', $event->name); + // Get events for user that belongs to groups A and B and has no user override events. + $this->setUser($group12student); + $events = calendar_get_events($timestart, $timeend, $group12student->id, $groups, $course->id); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertEquals('Assignment 1 due date - Group B override', $event->name); + // Get events for user that belongs to group A and has no user override events. + $this->setUser($group1student); + $events = calendar_get_events($timestart, $timeend, $group1student->id, $groups, $course->id); + $this->assertCount(1, $events); + $event = reset($events); + $this->assertEquals('Assignment 1 due date - Group A override', $event->name); + // Add repeating events. + $repeatingevents = [ + [ + 'name' => 'Repeating site event', + 'description' => '', + 'format' => 1, + 'courseid' => SITEID, + 'groupid' => 0, + 'userid' => 2, + 'repeatid' => $event->id, + 'modulename' => '0', + 'instance' => 0, + 'eventtype' => 'site', + 'timestart' => $now + 86400, + 'timeduration' => 0, + 'visible' => 1, + ], + [ + 'name' => 'Repeating site event', + 'description' => '', + 'format' => 1, + 'courseid' => SITEID, + 'groupid' => 0, + 'userid' => 2, + 'repeatid' => $event->id, + 'modulename' => '0', + 'instance' => 0, + 'eventtype' => 'site', + 'timestart' => $now + (2 * 86400), + 'timeduration' => 0, + 'visible' => 1, + ], + ]; + foreach ($repeatingevents as $event) { + calendar_event::create($event, false); + } + // Make sure repeating events are not filtered out. + $events = calendar_get_events($timestart, $timeend, true, true, true); + $this->assertCount(3, $events); + } + + public function test_get_course_cached() { + // Setup some test courses. + $course1 = $this->getDataGenerator()->create_course(); + $course2 = $this->getDataGenerator()->create_course(); + $course3 = $this->getDataGenerator()->create_course(); + + // Load courses into cache. + $coursecache = null; + calendar_get_course_cached($coursecache, $course1->id); + calendar_get_course_cached($coursecache, $course2->id); + calendar_get_course_cached($coursecache, $course3->id); + + // Verify the cache. + $this->assertArrayHasKey($course1->id, $coursecache); + $cachedcourse1 = $coursecache[$course1->id]; + $this->assertEquals($course1->id, $cachedcourse1->id); + $this->assertEquals($course1->shortname, $cachedcourse1->shortname); + $this->assertEquals($course1->fullname, $cachedcourse1->fullname); + + $this->assertArrayHasKey($course2->id, $coursecache); + $cachedcourse2 = $coursecache[$course2->id]; + $this->assertEquals($course2->id, $cachedcourse2->id); + $this->assertEquals($course2->shortname, $cachedcourse2->shortname); + $this->assertEquals($course2->fullname, $cachedcourse2->fullname); + + $this->assertArrayHasKey($course3->id, $coursecache); + $cachedcourse3 = $coursecache[$course3->id]; + $this->assertEquals($course3->id, $cachedcourse3->id); + $this->assertEquals($course3->shortname, $cachedcourse3->shortname); + $this->assertEquals($course3->fullname, $cachedcourse3->fullname); + } + + /** + * Test the update_subscription() function. + */ + public function test_update_subscription() { + $this->resetAfterTest(true); + + $subscription = new stdClass(); + $subscription->eventtype = 'site'; + $subscription->name = 'test'; + $id = calendar_add_subscription($subscription); + + $subscription = calendar_get_subscription($id); + $subscription->name = 'awesome'; + calendar_update_subscription($subscription); + $sub = calendar_get_subscription($id); + $this->assertEquals($subscription->name, $sub->name); + + $subscription = calendar_get_subscription($id); + $subscription->name = 'awesome2'; + $subscription->pollinterval = 604800; + calendar_update_subscription($subscription); + $sub = calendar_get_subscription($id); + $this->assertEquals($subscription->name, $sub->name); + $this->assertEquals($subscription->pollinterval, $sub->pollinterval); + + $subscription = new stdClass(); + $subscription->name = 'awesome4'; + $this->expectException('coding_exception'); + calendar_update_subscription($subscription); + } + + public function test_add_subscription() { + global $DB, $CFG; + + require_once($CFG->dirroot . '/lib/bennu/bennu.inc.php'); + + $this->resetAfterTest(true); + + // Test for Microsoft Outlook 2010. + $subscription = new stdClass(); + $subscription->name = 'Microsoft Outlook 2010'; + $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; + $subscription->eventtype = 'site'; + $id = calendar_add_subscription($subscription); + + $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/ms_outlook_2010.ics'); + $ical = new iCalendar(); + $ical->unserialize($calendar); + $this->assertEquals($ical->parser_errors, array()); + + $sub = calendar_get_subscription($id); + calendar_import_icalendar_events($ical, $sub->courseid, $sub->id); + $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); + $this->assertEquals($count, 1); + + // Test for OSX Yosemite. + $subscription = new stdClass(); + $subscription->name = 'OSX Yosemite'; + $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; + $subscription->eventtype = 'site'; + $id = calendar_add_subscription($subscription); + + $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/osx_yosemite.ics'); + $ical = new iCalendar(); + $ical->unserialize($calendar); + $this->assertEquals($ical->parser_errors, array()); + + $sub = calendar_get_subscription($id); + calendar_import_icalendar_events($ical, $sub->courseid, $sub->id); + $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); + $this->assertEquals($count, 1); + + // Test for Google Gmail. + $subscription = new stdClass(); + $subscription->name = 'Google Gmail'; + $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; + $subscription->eventtype = 'site'; + $id = calendar_add_subscription($subscription); + + $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/google_gmail.ics'); + $ical = new iCalendar(); + $ical->unserialize($calendar); + $this->assertEquals($ical->parser_errors, array()); + + $sub = calendar_get_subscription($id); + calendar_import_icalendar_events($ical, $sub->courseid, $sub->id); + $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); + $this->assertEquals($count, 1); + } +} \ No newline at end of file diff --git a/calendar/view.php b/calendar/view.php index 8df030f1046..a55aee6e195 100644 --- a/calendar/view.php +++ b/calendar/view.php @@ -91,7 +91,7 @@ if ($courseid != SITEID && !empty($courseid)) { navigation_node::override_active_url(new moodle_url('/course/view.php', array('id' => $course->id))); } else { $course = get_site(); - $courses = \core_calendar\api::get_default_courses(); + $courses = calendar_get_default_courses(); $issite = true; } @@ -158,7 +158,7 @@ switch($view) { echo $OUTPUT->container_start('bottom'); if (!empty($CFG->enablecalendarexport)) { echo $OUTPUT->single_button(new moodle_url('export.php', array('course'=>$courseid)), get_string('exportcalendar', 'calendar')); - if (\core_calendar\api::can_add_event_to_course($course)) { + if (calendar_user_can_add_event($course)) { echo $OUTPUT->single_button(new moodle_url('/calendar/managesubscriptions.php', array('course'=>$courseid)), get_string('managesubscriptions', 'calendar')); } if (isloggedin()) { diff --git a/lib/classes/task/calendar_cron_task.php b/lib/classes/task/calendar_cron_task.php index f387ad572a1..bf7f9577e22 100644 --- a/lib/classes/task/calendar_cron_task.php +++ b/lib/classes/task/calendar_cron_task.php @@ -62,7 +62,7 @@ class calendar_cron_task extends scheduled_task { foreach ($subscriptions as $sub) { mtrace("Updating calendar subscription {$sub->name} in course {$sub->courseid}"); try { - $log = \core_calendar\api::update_subscription_events($sub->id); + $log = calendar_update_subscription_events($sub->id); mtrace(trim(strip_tags($log))); } catch (\moodle_exception $ex) { mtrace('Error updating calendar subscription: ' . $ex->getMessage()); diff --git a/lib/tests/calendar_cron_task_test.php b/lib/tests/calendar_cron_task_test.php index 0e86025b5df..fa410b9ecf3 100644 --- a/lib/tests/calendar_cron_task_test.php +++ b/lib/tests/calendar_cron_task_test.php @@ -53,7 +53,7 @@ class core_calendar_cron_task_testcase extends advanced_testcase { $subscription->url = $subscriptionurl; $subscription->pollinterval = 86400; $subscription->lastupdated = 0; - \core_calendar\api::add_subscription($subscription); + calendar_add_subscription($subscription); $this->expectOutputRegex('/Events imported: .* Events updated:/'); $task = new \core\task\calendar_cron_task(); @@ -70,7 +70,7 @@ class core_calendar_cron_task_testcase extends advanced_testcase { $subscription->url = 'brokenurl'; $subscription->pollinterval = 86400; $subscription->lastupdated = 0; - \core_calendar\api::add_subscription($subscription); + calendar_add_subscription($subscription); $this->expectOutputRegex('/Error updating calendar subscription: The given iCal URL is invalid/'); $task = new \core\task\calendar_cron_task(); diff --git a/user/calendar.php b/user/calendar.php index 23b733d2afd..ef810f4dd54 100644 --- a/user/calendar.php +++ b/user/calendar.php @@ -46,7 +46,7 @@ if (isset($CFG->calendar_maxevents)) { $calendarform = new core_user\form\calendar_form(null, array('userid' => $user->id)); $user->timeformat = get_user_preferences('calendar_timeformat', ''); -$user->startwday = \core_calendar\api::get_starting_weekday(); +$user->startwday = calendar_get_starting_weekday(); $user->maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents); $user->lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead); $user->persistflt = get_user_preferences('calendar_persistflt', 0);