From e41f37dd4f531d6b6c1e0a6a7b48f1e6fcab1a88 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 6 Oct 2023 16:12:35 +0200 Subject: [locationinfo] text-muted for "inherited" up-arrow --- .../locationinfo/inc/icalcoursebackend.inc.php | 2 +- .../locationinfo/inc/icalevent.inc.php | 447 ++++++++++++--------- .../locationinfo/inc/icalparser.inc.php | 144 +++---- modules-available/locationinfo/page.inc.php | 1 + .../locationinfo/templates/page-locations.html | 2 +- 5 files changed, 308 insertions(+), 288 deletions(-) diff --git a/modules-available/locationinfo/inc/icalcoursebackend.inc.php b/modules-available/locationinfo/inc/icalcoursebackend.inc.php index 50f1881a..44691bb4 100644 --- a/modules-available/locationinfo/inc/icalcoursebackend.inc.php +++ b/modules-available/locationinfo/inc/icalcoursebackend.inc.php @@ -48,7 +48,7 @@ abstract class ICalCourseBackend extends CourseBackend * @param callable $errorFunc * @return ICalEvent[]|null all events for this room in the range -7 days to +7 days, or NULL on error */ - protected function downloadIcal(string $roomId) + protected function downloadIcal(string $roomId): ?array { if (!$this->isOK()) return null; diff --git a/modules-available/locationinfo/inc/icalevent.inc.php b/modules-available/locationinfo/inc/icalevent.inc.php index 1fb586ee..0c234f48 100644 --- a/modules-available/locationinfo/inc/icalevent.inc.php +++ b/modules-available/locationinfo/inc/icalevent.inc.php @@ -2,199 +2,256 @@ class ICalEvent { - // phpcs:disable Generic.Arrays.DisallowLongArraySyntax - - const HTML_TEMPLATE = '

%s: %s

'; - - /** - * https://www.kanzaki.com/docs/ical/summary.html - * - * @var $summary - */ - public $summary; - - /** - * https://www.kanzaki.com/docs/ical/dtstart.html - * - * @var $dtstart - */ - public $dtstart; - - /** - * https://www.kanzaki.com/docs/ical/dtend.html - * - * @var $dtend - */ - public $dtend; - - /** - * https://www.kanzaki.com/docs/ical/duration.html - * - * @var $duration - */ - public $duration; - - /** - * https://www.kanzaki.com/docs/ical/dtstamp.html - * - * @var $dtstamp - */ - public $dtstamp; - - /** - * https://www.kanzaki.com/docs/ical/uid.html - * - * @var $uid - */ - public $uid; - - /** - * https://www.kanzaki.com/docs/ical/created.html - * - * @var $created - */ - public $created; - - /** - * https://www.kanzaki.com/docs/ical/lastModified.html - * - * @var $lastmodified - */ - public $lastmodified; - - /** - * https://www.kanzaki.com/docs/ical/description.html - * - * @var $description - */ - public $description; - - /** - * https://www.kanzaki.com/docs/ical/location.html - * - * @var $location - */ - public $location; - - /** - * https://www.kanzaki.com/docs/ical/sequence.html - * - * @var $sequence - */ - public $sequence; - - /** - * https://www.kanzaki.com/docs/ical/status.html - * - * @var $status - */ - public $status; - - /** - * https://www.kanzaki.com/docs/ical/transp.html - * - * @var $transp - */ - public $transp; - - /** - * https://www.kanzaki.com/docs/ical/organizer.html - * - * @var $organizer - */ - public $organizer; - - /** - * https://www.kanzaki.com/docs/ical/attendee.html - * - * @var $attendee - */ - public $attendee; - - /** - * Creates the Event object - * - * @param array $data - * @return void - */ - public function __construct(array $data = array()) - { - foreach ($data as $key => $value) { - $variable = self::snakeCase($key); - $this->{$variable} = self::prepareData($value); - } - } - - /** - * Prepares the data for output - * - * @param mixed $value - * @return mixed - */ - protected function prepareData($value) - { - if (is_string($value)) { - return stripslashes(trim(str_replace('\n', "\n", $value))); - } elseif (is_array($value)) { - return array_map('self::prepareData', $value); - } - - return $value; - } - - /** - * Returns Event data excluding anything blank - * within an HTML template - * - * @param string $html HTML template to use - * @return string - */ - public function printData($html = self::HTML_TEMPLATE) - { - $data = array( - 'SUMMARY' => $this->summary, - 'DTSTART' => $this->dtstart, - 'DTEND' => $this->dtend, - 'DURATION' => $this->duration, - 'DTSTAMP' => $this->dtstamp, - 'UID' => $this->uid, - 'CREATED' => $this->created, - 'LAST-MODIFIED' => $this->lastmodified, - 'DESCRIPTION' => $this->description, - 'LOCATION' => $this->location, - 'SEQUENCE' => $this->sequence, - 'STATUS' => $this->status, - 'TRANSP' => $this->transp, - 'ORGANISER' => $this->organizer, - 'ATTENDEE(S)' => $this->attendee, - ); - - // Remove any blank values - $data = array_filter($data); - - $output = ''; - - foreach ($data as $key => $value) { - $output .= sprintf($html, $key, $value); - } - - return $output; - } - - /** - * Converts the given input to snake_case - * - * @param string $input - * @param string $glue - * @param string $separator - * @return string - */ - protected static function snakeCase($input, $glue = '_', $separator = '-') - { - $input = preg_split('/(?<=[a-z])(?=[A-Z])/x', $input); - $input = implode($glue, $input); - $input = str_replace($separator, $glue, $input); - - return strtolower($input); - } + // phpcs:disable Generic.Arrays.DisallowLongArraySyntax + + const HTML_TEMPLATE = '

%s: %s

'; + + /** + * https://www.kanzaki.com/docs/ical/summary.html + * + * @var string + */ + public $summary; + + /** + * https://www.kanzaki.com/docs/ical/dtstart.html + * + * @var string + */ + public $dtstart; + + /** + * https://www.kanzaki.com/docs/ical/dtend.html + * + * @var string + */ + public $dtend; + + /** + * https://www.kanzaki.com/docs/ical/duration.html + * + * @var string + */ + public $duration; + + /** + * https://www.kanzaki.com/docs/ical/dtstamp.html + * + * @var string + */ + public $dtstamp; + + /** + * When the event starts, represented as a timezone-adjusted string + * + * @var string + */ + public $dtstart_tz; + + /** + * When the event ends, represented as a timezone-adjusted string + * + * @var string + */ + public $dtend_tz; + + /** + * https://www.kanzaki.com/docs/ical/uid.html + * + * @var string + */ + public $uid; + + /** + * https://www.kanzaki.com/docs/ical/created.html + * + * @var string + */ + public $created; + + /** + * https://www.kanzaki.com/docs/ical/lastModified.html + * + * @var string + */ + public $last_modified; + + /** + * https://www.kanzaki.com/docs/ical/description.html + * + * @var string + */ + public $description; + + /** + * https://www.kanzaki.com/docs/ical/location.html + * + * @var string + */ + public $location; + + /** + * https://www.kanzaki.com/docs/ical/sequence.html + * + * @var string + */ + public $sequence; + + /** + * https://www.kanzaki.com/docs/ical/status.html + * + * @var string + */ + public $status; + + /** + * https://www.kanzaki.com/docs/ical/transp.html + * + * @var string + */ + public $transp; + + /** + * https://www.kanzaki.com/docs/ical/organizer.html + * + * @var string + */ + public $organizer; + + /** + * https://www.kanzaki.com/docs/ical/attendee.html + * + * @var string + */ + public $attendee; + + /** + * Manage additional properties + * + * @var array + */ + private $additionalProperties = array(); + + /** + * Creates the Event object + * + * @param array $data + * @return void + */ + public function __construct(array $data = array()) + { + foreach ($data as $key => $value) { + $variable = self::snakeCase($key); + if (property_exists($this, $variable)) { + $this->{$variable} = $this->prepareData($value); + } else { + $this->additionalProperties[$variable] = $this->prepareData($value); + } + } + } + + /** + * Magic getter method + * + * @param string $additionalPropertyName + * @return mixed + */ + public function __get($additionalPropertyName) + { + if (array_key_exists($additionalPropertyName, $this->additionalProperties)) { + return $this->additionalProperties[$additionalPropertyName]; + } + + return null; + } + + /** + * Magic isset method + * + * @param string $name + * @return boolean + */ + public function __isset($name) + { + return is_null($this->$name) === false; + } + + /** + * Prepares the data for output + * + * @param mixed $value + * @return mixed + */ + protected function prepareData($value) + { + if (is_string($value)) { + return stripslashes(trim(str_replace('\n', "\n", $value))); + } + + if (is_array($value)) { + return array_map(function ($value) { + return $this->prepareData($value); + }, $value); + } + + return $value; + } + + /** + * Returns Event data excluding anything blank + * within an HTML template + * + * @param string $html HTML template to use + * @return string + */ + public function printData($html = self::HTML_TEMPLATE) + { + $data = array( + 'SUMMARY' => $this->summary, + 'DTSTART' => $this->dtstart, + 'DTEND' => $this->dtend, + 'DTSTART_TZ' => $this->dtstart_tz, + 'DTEND_TZ' => $this->dtend_tz, + 'DURATION' => $this->duration, + 'DTSTAMP' => $this->dtstamp, + 'UID' => $this->uid, + 'CREATED' => $this->created, + 'LAST-MODIFIED' => $this->last_modified, + 'DESCRIPTION' => $this->description, + 'LOCATION' => $this->location, + 'SEQUENCE' => $this->sequence, + 'STATUS' => $this->status, + 'TRANSP' => $this->transp, + 'ORGANISER' => $this->organizer, + 'ATTENDEE(S)' => $this->attendee, + ); + + // Remove any blank values + $data = array_filter($data); + + $output = ''; + + foreach ($data as $key => $value) { + $output .= sprintf($html, $key, $value); + } + + return $output; + } + + /** + * Converts the given input to snake_case + * + * @param string $input + * @param string $glue + * @param string $separator + * @return string + */ + protected static function snakeCase($input, $glue = '_', $separator = '-') + { + $input = preg_split('/(?<=[a-z])(?=[A-Z])/x', $input); + $input = implode($glue, $input); + $input = str_replace($separator, $glue, $input); + + return strtolower($input); + } } diff --git a/modules-available/locationinfo/inc/icalparser.inc.php b/modules-available/locationinfo/inc/icalparser.inc.php index 0be8777b..69ff84d0 100644 --- a/modules-available/locationinfo/inc/icalparser.inc.php +++ b/modules-available/locationinfo/inc/icalparser.inc.php @@ -23,7 +23,6 @@ class ICalParser const ICAL_DATE_TIME_TEMPLATE = 'TZID=%s:'; const ISO_8601_WEEK_START = 'MO'; const RECURRENCE_EVENT = 'Generated recurrence event'; - const TIME_FORMAT = 'His'; const TIME_ZONE_UTC = 'UTC'; const UNIX_FORMAT = 'U'; @@ -481,15 +480,12 @@ class ICalParser /** * Creates the ICal object * - * @param mixed $files * @param array $options * @return void * @throws Exception */ public function __construct(array $options = array()) { - ini_set('auto_detect_line_endings', '1'); - foreach ($options as $option => $value) { if (in_array($option, self::$configurableOptions)) { $this->{$option} = $value; @@ -501,10 +497,7 @@ class ICalParser $this->defaultTimeZone = date_default_timezone_get(); } - // Ideally you would use `PHP_INT_MIN` from PHP 7 - $php_int_min = -2147483648; - - $this->windowMinTimestamp = is_null($this->filterDaysBefore) ? $php_int_min : (new DateTime('now'))->sub(new DateInterval('P' . $this->filterDaysBefore . 'D'))->getTimestamp(); + $this->windowMinTimestamp = is_null($this->filterDaysBefore) ? PHP_INT_MIN : (new DateTime('now'))->sub(new DateInterval('P' . $this->filterDaysBefore . 'D'))->getTimestamp(); $this->windowMaxTimestamp = is_null($this->filterDaysAfter) ? PHP_INT_MAX : (new DateTime('now'))->add(new DateInterval('P' . $this->filterDaysAfter . 'D'))->getTimestamp(); $this->shouldFilterByWindow = !is_null($this->filterDaysBefore) || !is_null($this->filterDaysAfter); @@ -516,7 +509,7 @@ class ICalParser * * @param string $data */ - public function feedData($data) + public function feedData(string $data) { $this->feedBuffer .= $data; $start = 0; @@ -581,7 +574,7 @@ class ICalParser * * @return bool */ - public function isValid() + public function isValid(): bool { return $this->hasSeenStart; } @@ -591,7 +584,7 @@ class ICalParser * * @param string $line */ - protected function handleLine($line) + protected function handleLine(string $line) { $line = rtrim($line); // Trim trailing whitespace $line = $this->removeUnprintableChars($line); @@ -602,18 +595,18 @@ class ICalParser $add = $this->keyValueFromString($line); - if ($add === false) { + if ($add === null) { return; } - $keyword = $add[0]; + $keyword = $add[0]; // string $values = $add[1]; // May be an array containing multiple values if (!is_array($values)) { if (!empty($values)) { $values = array($values); // Make an array as not already $blankArray = array(); // Empty placeholder array - array_push($values, $blankArray); + $values[] = $blankArray; } else { $values = array(); // Use blank array to ignore this line } @@ -752,16 +745,9 @@ class ICalParser foreach ($events as $key => $anEvent) { if ($anEvent === null) { unset($events[$key]); - - continue; - } - - if ($this->doesEventStartOutsideWindow($anEvent)) { + } elseif ($this->doesEventStartOutsideWindow($anEvent)) { $this->eventCount--; - unset($events[$key]); - - continue; } } @@ -776,7 +762,7 @@ class ICalParser * @param array $event * @return boolean */ - protected function doesEventStartOutsideWindow(array $event) + protected function doesEventStartOutsideWindow(array $event): bool { return !isset($event['DTSTART']) || !$this->isValidDate($event['DTSTART']) || $this->isOutOfRange($event['DTSTART'], $this->windowMinTimestamp, $this->windowMaxTimestamp); @@ -790,44 +776,23 @@ class ICalParser * @param integer $maxTimestamp * @return boolean */ - protected function isOutOfRange($calendarDate, $minTimestamp, $maxTimestamp) + protected function isOutOfRange(string $calendarDate, int $minTimestamp, int $maxTimestamp): bool { $timestamp = strtotime(explode('T', $calendarDate)[0]); return $timestamp < $minTimestamp || $timestamp > $maxTimestamp; } - /** - * Unfolds an iCal file in preparation for parsing - * (https://icalendar.org/iCalendar-RFC-5545/3-1-content-lines.html) - * - * @param array $lines - * @return array - */ - protected function unfold(array $lines) - { - $string = implode(PHP_EOL, $lines); - $string = preg_replace('/' . PHP_EOL . '[ \t]/', '', $string); - - $lines = explode(PHP_EOL, $string); - - return $lines; - } - /** * Add one key and value pair to the `$this->cal` array * * @param string $component - * @param string|boolean $keyword - * @param string $value + * @param string $keyword + * @param string|string[] $value * @return void */ - protected function addCalendarComponentWithKeyAndValue($component, $keyword, $value) + protected function addCalendarComponentWithKeyAndValue(string $component, string $keyword, $value) { - if ($keyword == false) { - $keyword = $this->lastKeyword; - } - switch ($component) { case 'VALARM': $key1 = 'VEVENT'; @@ -840,7 +805,7 @@ class ICalParser if (is_array($value)) { // Add array of properties to the end - array_push($this->cal[$key1][$key2][$key3]["{$keyword}_array"], $value); + $this->cal[$key1][$key2][$key3]["{$keyword}_array"][] = $value; } else { if (!isset($this->cal[$key1][$key2][$key3][$keyword])) { $this->cal[$key1][$key2][$key3][$keyword] = $value; @@ -862,7 +827,7 @@ class ICalParser if (is_array($value)) { // Add array of properties to the end - array_push($this->cal[$key1][$key2]["{$keyword}_array"], $value); + $this->cal[$key1][$key2]["{$keyword}_array"][] = $value; } else { if (!isset($this->cal[$key1][$key2][$keyword])) { $this->cal[$key1][$key2][$keyword] = $value; @@ -882,7 +847,7 @@ class ICalParser if ($keyword === 'DURATION') { try { $duration = new DateInterval($value); - array_push($this->cal[$key1][$key2]["{$keyword}_array"], $duration); + $this->cal[$key1][$key2]["{$keyword}_array"][] = $duration; } catch (Exception $e) { error_log('Ignoring invalid duration ' . $value); } @@ -928,6 +893,7 @@ class ICalParser break; } + // Remove? $this->lastKeyword = $keyword; } @@ -935,9 +901,9 @@ class ICalParser * Gets the key value pair from an iCal string * * @param string $text - * @return array|boolean + * @return ?array */ - protected function keyValueFromString($text) + protected function keyValueFromString(string $text): ?array { $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); @@ -974,14 +940,14 @@ class ICalParser } if (count($matches) === 0) { - return false; + return null; } - if (preg_match('/^([A-Z-]+)([;][\w\W]*)?$/', $matches[1])) { + if (preg_match('/^([A-Z-]+)(;[\w\W]*)?$/', $matches[1])) { $matches = array_splice($matches, 1, 2); // Remove first match and re-align ordering // Process properties - if (preg_match('/([A-Z-]+)[;]([\w\W]*)/', $matches[0], $properties)) { + if (preg_match('/([A-Z-]+);([\w\W]*)/', $matches[0], $properties)) { // Remove first match array_shift($properties); // Fix to ignore everything in keyword after a ; (e.g. Language, TZID, etc.) @@ -1024,7 +990,7 @@ class ICalParser return $matches; } else { - return false; // Ignore this match + return null; // Ignore this match } } @@ -1034,7 +1000,7 @@ class ICalParser * @param string $icalDate * @return DateTime */ - public function iCalDateToDateTime($icalDate) + public function iCalDateToDateTime(string $icalDate): DateTime { /** * iCal times may be in 3 formats, (https://www.kanzaki.com/docs/ical/dateTime.html) @@ -1091,7 +1057,7 @@ class ICalParser * @param string $icalDate * @return integer */ - public function iCalDateToUnixTimestamp($icalDate) + public function iCalDateToUnixTimestamp(string $icalDate): int { return $this->iCalDateToDateTime($icalDate)->getTimestamp(); } @@ -1104,7 +1070,7 @@ class ICalParser * @param string $format * @return string|boolean */ - public function iCalDateWithTimeZone(array $event, $key, $format = self::DATE_TIME_FORMAT) + public function iCalDateWithTimeZone(array $event, string $key, string $format = self::DATE_TIME_FORMAT) { if (!isset($event["{$key}_array"]) || !isset($event[$key])) { return false; @@ -1141,7 +1107,6 @@ class ICalParser if (empty($this->cal['VEVENT'])) return; $events =& $this->cal['VEVENT']; - $checks = null; foreach ($events as $key => $anEvent) { foreach (array('DTSTART', 'DTEND', 'RECURRENCE-ID') as $type) { @@ -1175,23 +1140,20 @@ class ICalParser $eventKeysToRemove = array(); foreach ($events as $key => $event) { - $checks[] = !isset($event['RECURRENCE-ID']); - $checks[] = isset($event['UID']); - $checks[] = isset($event['UID']) && isset($this->alteredRecurrenceInstances[$event['UID']]); + $checks = !isset($event['RECURRENCE-ID']) + && isset($event['UID']) && isset($this->alteredRecurrenceInstances[$event['UID']]); - if ((bool)array_product($checks)) { + if ($checks) { $eventDtstartUnix = $this->iCalDateToUnixTimestamp($event['DTSTART_array'][3]); // phpcs:ignore CustomPHPCS.ControlStructures.AssignmentInCondition if (($alteredEventKey = array_search($eventDtstartUnix, $this->alteredRecurrenceInstances[$event['UID']])) !== false) { $eventKeysToRemove[] = $alteredEventKey; - $alteredEvent = array_replace_recursive($events[$key], $events[$alteredEventKey]); + $alteredEvent = array_replace_recursive($event, $events[$alteredEventKey]); $this->alteredRecurrenceInstances[$event['UID']]['altered-event'] = array($key => $alteredEvent); } } - - unset($checks); } foreach ($eventKeysToRemove as $eventKeyToRemove) { @@ -1568,7 +1530,7 @@ class ICalParser * @param DateTime $initialDateTime * @return array */ - protected function getDaysOfMonthMatchingByDayRRule(array $byDays, $initialDateTime) + protected function getDaysOfMonthMatchingByDayRRule(array $byDays, DateTime $initialDateTime): array { $matchingDays = array(); @@ -1628,7 +1590,7 @@ class ICalParser * @param array $valuesList * @return array */ - protected function filterValuesUsingBySetPosRRule(array $bySetPos, array $valuesList) + protected function filterValuesUsingBySetPosRRule(array $bySetPos, array $valuesList): array { $filteredMatches = array(); @@ -1688,7 +1650,7 @@ class ICalParser * * @return ICalEvent[] */ - public function events() + public function events(): array { if (empty($this->cal) || empty($this->cal['VEVENT'])) return []; @@ -1706,9 +1668,9 @@ class ICalParser * * @return string */ - public function calendarName() + public function calendarName(): string { - return isset($this->cal['VCALENDAR']['X-WR-CALNAME']) ? $this->cal['VCALENDAR']['X-WR-CALNAME'] : ''; + return $this->cal['VCALENDAR']['X-WR-CALNAME'] ?? ''; } /** @@ -1716,9 +1678,9 @@ class ICalParser * * @return string */ - public function calendarDescription() + public function calendarDescription(): string { - return isset($this->cal['VCALENDAR']['X-WR-CALDESC']) ? $this->cal['VCALENDAR']['X-WR-CALDESC'] : ''; + return $this->cal['VCALENDAR']['X-WR-CALDESC'] ?? ''; } /** @@ -1727,7 +1689,7 @@ class ICalParser * @param boolean $ignoreUtc * @return string */ - public function calendarTimeZone($ignoreUtc = false) + public function calendarTimeZone(bool $ignoreUtc = false): ?string { if (isset($this->cal['VCALENDAR']['X-WR-TIMEZONE'])) { $timeZone = $this->cal['VCALENDAR']['X-WR-TIMEZONE']; @@ -1754,11 +1716,11 @@ class ICalParser * * @return array */ - public function freeBusyEvents() + public function freeBusyEvents(): array { $array = $this->cal; - return isset($array['VFREEBUSY']) ? $array['VFREEBUSY'] : array(); + return $array['VFREEBUSY'] ?? array(); } /** @@ -1784,7 +1746,7 @@ class ICalParser * @return array * @throws Exception */ - public function eventsFromRange($rangeStart = null, $rangeEnd = null) + public function eventsFromRange(string $rangeStart = null, string $rangeEnd = null): array { // Sort events before processing range $events = $this->sortEventsWithOrder($this->events()); @@ -1857,7 +1819,7 @@ class ICalParser * @param integer $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING * @return array */ - public function sortEventsWithOrder(array $events, $sortOrder = SORT_ASC) + public function sortEventsWithOrder(array $events, int $sortOrder = SORT_ASC): array { $extendedEvents = array(); $timestamp = array(); @@ -1878,7 +1840,7 @@ class ICalParser * @param string $timeZone * @return boolean */ - protected function isValidTimeZoneId($timeZone) + protected function isValidTimeZoneId(string $timeZone): bool { return $this->isValidIanaTimeZoneId($timeZone) !== false || $this->isValidCldrTimeZoneId($timeZone) !== false @@ -1891,7 +1853,7 @@ class ICalParser * @param string $timeZone * @return boolean */ - protected function isValidIanaTimeZoneId($timeZone) + protected function isValidIanaTimeZoneId(string $timeZone): bool { if (in_array($timeZone, $this->validIanaTimeZones)) { return true; @@ -1923,7 +1885,7 @@ class ICalParser * @param string $timeZone * @return boolean */ - public function isValidCldrTimeZoneId($timeZone) + public function isValidCldrTimeZoneId(string $timeZone): bool { return array_key_exists(html_entity_decode($timeZone), self::$cldrTimeZonesMap); } @@ -1934,7 +1896,7 @@ class ICalParser * @param string $timeZone * @return boolean */ - public function isValidWindowsTimeZoneId($timeZone) + public function isValidWindowsTimeZoneId(string $timeZone): bool { return array_key_exists(html_entity_decode($timeZone), self::$windowsTimeZonesMap); } @@ -1947,7 +1909,7 @@ class ICalParser * @param string $format * @return integer|DateTime */ - protected function parseDuration($date, $duration, $format = self::UNIX_FORMAT) + protected function parseDuration(string $date, DateInterval $duration, string $format = self::UNIX_FORMAT) { $dateTime = date_create($date); $dateTime->modify("{$duration->y} year"); @@ -1974,7 +1936,7 @@ class ICalParser * @param string $data * @return string */ - protected function removeUnprintableChars($data) + protected function removeUnprintableChars(string $data): string { return preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $data); } @@ -1986,7 +1948,7 @@ class ICalParser * @param string $candidateText * @return string */ - protected function escapeParamText($candidateText) + protected function escapeParamText(string $candidateText): string { if (strpbrk($candidateText, ':;,') !== false) { return '"' . $candidateText . '"'; @@ -2002,7 +1964,7 @@ class ICalParser * @param array $event * @return array */ - public function parseExdates(array $event) + public function parseExdates(array $event): array { if (empty($event['EXDATE_array'])) { return array(); @@ -2046,7 +2008,7 @@ class ICalParser * @param string $value * @return boolean */ - public function isValidDate($value) + public function isValidDate(string $value): bool { if (!$value) { return false; @@ -2065,10 +2027,10 @@ class ICalParser * Returns a `DateTimeZone` object based on a string containing a time zone name. * Falls back to the default time zone if string passed not a recognised time zone. * - * @param string $timeZoneString + * @param DateTimeZone|string $timeZoneString * @return DateTimeZone */ - public function timeZoneStringToDateTimeZone($timeZoneString) + public function timeZoneStringToDateTimeZone($timeZoneString): DateTimeZone { if ($timeZoneString instanceof DateTimeZone) return $timeZoneString; diff --git a/modules-available/locationinfo/page.inc.php b/modules-available/locationinfo/page.inc.php index 4e598d68..f81fca13 100644 --- a/modules-available/locationinfo/page.inc.php +++ b/modules-available/locationinfo/page.inc.php @@ -549,6 +549,7 @@ class Page_LocationInfo extends Page } $locations[$locid] += array( 'openingGlyph' => $glyph, + 'strong' => $glyph === 'ok', 'backend' => $backend, 'lastCalendarUpdate' => Util::prettyTime($row['lastcalendarupdate']), // TODO 'backendMissing' => !CourseBackend::exists($row['servertype']), diff --git a/modules-available/locationinfo/templates/page-locations.html b/modules-available/locationinfo/templates/page-locations.html index fa2e3a2d..c09b5336 100644 --- a/modules-available/locationinfo/templates/page-locations.html +++ b/modules-available/locationinfo/templates/page-locations.html @@ -35,7 +35,7 @@ {{/backend}} - + {{/list}} -- cgit v1.2.3-55-g7522