diff --git a/public/krautspace.ics b/public/krautspace.ics index 7175588..77211ba 100644 --- a/public/krautspace.ics +++ b/public/krautspace.ics @@ -14,13 +14,13 @@ BEGIN:VEVENT SUMMARY:"Chaostreff" UID:0000000002@kraut.space CLASS:PUBLIC -DESCRIPTION:"Offene Runde" +DESCRIPTION:Offene Runde DTEND;TZID=CET:20200623T235900 DTSTAMP;TZID=CET:20200623T125900 DTSTART;TZID=CET:20200623T200000 GEO:50.9292035\,11.5825763 -LOCATION:"Krautgasse 26\, 07743 Jena" -URL;VALUE="HTTPS://kraut.space/chaostreff" +LOCATION:Krautgasse 26, 07743 Jena und online unter https://kraut.space/chaostreff +URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:chaostreff:start ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space REFRESH-INTERVAL;VALUE=DURATION:P1W RRULE:FREQ=WEEKLY @@ -29,28 +29,28 @@ BEGIN:VEVENT SUMMARY:"Brettspielrunde" UID:0000000003@kraut.space CLASS:PUBLIC -DESCRIPTION:"Brettspielerei" -DTEND;TZID=CET:20220518T235900 -DTSTAMP;TZID=CET:20220518T125900 -DTSTART;TZID=CET:20220518T200000 +DESCRIPTION:Brettspielerei +DTSTAMP;TZID=CET:20221116T125900 +DTSTART;TZID=CET:20221116T200000 +DTEND;TZID=CET:20221116T235900 GEO:50.9292035\,11.5825763 -LOCATION:"Krautgasse 26\, 07743 Jena" -URL;VALUE="HTTPS://kraut.space/brettspielerei" +LOCATION:Krautgasse 26, 07743 Jena +URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:brettspielerei ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space REFRESH-INTERVAL;VALUE=DURATION:P1W -RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,36,38,40,42,44,46,48,50,52 +RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=WE;BYWEEKNO=2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,36,38,40,42,44,46,48,50,52 END:VEVENT BEGIN:VEVENT SUMMARY:"Linux User Group" UID:0000000004@kraut.space CLASS:PUBLIC -DESCRIPTION:"Alles rund um Linux" +DESCRIPTION:Alles rund um Linux DTEND;TZID=CET:20200625T235900 DTSTAMP;TZID=CET:20200623T125900 DTSTART;TZID=CET:20200625T200000 GEO:50.9292035\,11.5825763 -LOCATION:"Krautgasse 26\, 07743 Jena" -URL;VALUE="HTTPS://kraut.space/lug" +LOCATION:Krautgasse 26, 07743 Jena und online unter https://kraut.space/lug +URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:lug:start ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space REFRESH-INTERVAL;VALUE=DURATION:P1W RRULE:FREQ=WEEKLY @@ -59,13 +59,13 @@ BEGIN:VEVENT SUMMARY:"Gaming am Freitag" UID:0000000005@kraut.space CLASS:PUBLIC -DESCRIPTION:"Der Stammtisch für Videospielkultur" +DESCRIPTION:Der Stammtisch für Videospielkultur DTEND;TZID=CET:20220527T235900 DTSTAMP;TZID=CET:20220527T125900 DTSTART;TZID=CET:20220527T190000 GEO:50.9292035\,11.5825763 -LOCATION:"Krautgasse 26\, 07743 Jena" -URL;VALUE="HTTPS://kraut.space/gamingamfreitag" +LOCATION:Krautgasse 26, 07743 Jena +URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:gaming ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space REFRESH-INTERVAL;VALUE=DURATION:P1W RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53 @@ -74,15 +74,15 @@ BEGIN:VEVENT SUMMARY:"Kinderbasteln" UID:0000000006@kraut.space CLASS:PUBLIC -DESCRIPTION:"Natur und Technik für Vor- und Grundschulkinder" +DESCRIPTION:Natur und Technik für Vor- und Grundschulkinder DTEND;TZID=CET:20220611T120000 DTSTAMP;TZID=CET:20220611T100000 DTSTART;TZID=CET:20220611T100000 GEO:50.9292035\,11.5825763 -LOCATION:"Krautgasse 26\, 07743 Jena" -URL;VALUE="HTTPS://kraut.space/kinderbasteln" +LOCATION:Krautgasse 26, 07743 Jena +URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:kinderbasteln ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:basteln@kraut.space REFRESH-INTERVAL;VALUE=DURATION:P1W -RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53 +RRULE:WKST=MO;FREQ=WEEKLY;BYDAY=2SA,4SA END:VEVENT END:VCALENDAR diff --git a/src/getEvents.php b/src/getEvents.php index 35c91bd..c3b4fbb 100644 --- a/src/getEvents.php +++ b/src/getEvents.php @@ -1,344 +1,192 @@ data['DTSTART']; - /** @var string[] $eventDTStartValues */ - $eventDTStartValues = $eventDTStart->value; - $event_start = $eventDTStartValues[0] ?? ''; - $unix_start = $helper->fromiCaltoUnixDateTime($event_start); - $rrule = $event->data['RRULE']->value[0]; - - //todo rrule always set - if (EventIsPast($unix_start) === true AND isset ($rrule)) - { - $new_unix = calculateNextStart($unix_start, $rrule); - $date = date('Ymd', $new_unix); - $time = date('His', $new_unix); - $connector = 'T'; - $new_start = "{$date}{$connector}{$time}"; - $event->data['DTSTART']->value[0] = $new_start; - } +function initCalendar(): ?object { + try { + $data = file_get_contents(ICAL_FILE); + $vcalendar = VObject\Reader::read( + $data + ); + return $vcalendar; + } catch (Throwable $th) { + error_log("Failed to read calendar file."); + error_log($th->getMessage(), 0); + return null; } - - /** - * Eventliste nach Startdatum sortieren - */ - usort($events, 'compareEventStart'); - - /** - * Termine ausgeben - */ - foreach ($events as $event) - { - printListItem($event); - } - return true; } -function printListItem(ZCiCalNode $event): bool /** - * Die Ausgabefunktion für die Ausgabe der Termine als Liste. Hier wird die - * Zeitangabe des iCal-Formates in Datum, Uhrzeit und Wochentag umgewandelt. - * Anschließend erfolgt die Ausgabe der einzelnen Teile. + * Grabs all VEVENTS from vCalendar object, append they to a list and + * returns the list. + * + * @param vCalendar object + * @return list | null */ -{ - date_default_timezone_set("UTC"); - $helper = new ZDateHelper(); +function grabEvents(object $vcalendar): ?array { + $eventlist = []; + try { + foreach ($vcalendar->VEVENT as $event) { + $eventlist[] = $event; + } + } catch (Throwable $th) { + error_log("Failed to grab evens."); + error_log($th->getMessage(), 0); + return null; + } + return $eventlist; +} + +/** + * Becomes an instance from recurrency rule iterator and an datetime object. + * Until the iterators date is in future, we call for the next date. + * + * @param iterator object + * @param datetime + * @return datetime | null + */ +function getNextDate(object $rriterator, DateTime $now): ?DateTime { + foreach ($rriterator as $item) { + if ($item > $now) { + return $item; + } + } + return null; +} + +/** + * Main function to display the events. + * + * @param array + * @param object + */ +function printEvent(array $eventarray, object $date_helper) { + $start_datetime = $eventarray[0]; + $event = $eventarray[1]; + $day = toGerman($start_datetime->format("l")); + $start = $start_datetime->format("d.m.Y H:i"); $hyph = " - "; $uhr = " Uhr"; $komma = ", "; + $dateline = "{$day}{$komma}{$start}{$uhr}{$hyph}"; - $event_start = $event->data['DTSTART']->value[0]; - $event_url = lowerURL($event->data['URL']->parameter['value']); - $event_title = $event->data['SUMMARY']->value[0]; - $event_location = trim($event->data['LOCATION']->value[0], '"'); - $event_descr = trim($event->data['DESCRIPTION']->value[0], '"'); - - $unix = $helper->fromiCaltoUnixDateTime($event_start); - $event_date = date('d.m.Y', $unix); - $event_time = date('H:i', $unix); - $event_day = toGerman(date('l', $unix)); - $dateline = "{$event_day}{$komma}{$event_date}{$hyph}{$event_time}{$uhr}"; - - displayHeadline($dateline, $event_title); - displayLocation($event_location); - displayDescription($event_descr); - displayURL($event_url); - return true; -} - -function displayHeadline(string $dateline, $event_title): bool -{ - echo "\n
\n"; - echo "

" . $dateline . ": " . $event_title . "

\n"; - return true; -} - -function displayLocation(string $location): bool -{ - echo "\n"; - echo "
\n"; - return true; + if ($event->URL != "") { + printHeadline($dateline, $event->SUMMARY, $event->URL); + } else { + printHeadline($dateline, $event->SUMMARY); + } + if ($event->DESCRIPTION != "") { + printDescription($event->DESCRIPTION); + } + if ($event->LOCATION != "") { + printLocation($event->LOCATION); + } + printBottomline(); } /** - * Die Startfuktion für die Ausgabe der Termine als Tabelle in termine.php + * Outputs the opening tags for section and ul, the date and time, and + * summary. ifi a url is given, the summary is a link to the corresponding + * wiki page. + * + * @param string + * @param string */ - -function printEventTable(): bool -{ - $events = initEvents(); - printTableHead(); - foreach ($events as $event) - { - $event_array = getEventArray($event); - printTableItem($event_array); +function printHeadline(string $dateline, string $summary, string $url=null) { + echo("\n
"); + if ($url == null) { + echo("\n

$dateline$summary

"); + } else { + echo("\n

$dateline$summary

"); } - echo "\t\n"; - echo "\n"; - return true; -} - -function printTableHead() -{ - echo "\n\r\n"; - echo "\t\n"; - echo "\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\n"; - echo "\t\n"; - echo "\t\n"; -} - -function printTableItem($event_array): bool -{ - date_default_timezone_set("UTC"); - $time = $event_array['DTSTART']; - $helper = new ZDateHelper(); - $unix = $helper->fromiCaltoUnixDateTime($time); - $event_date = date('d.m.Y', $unix); - $event_time = date('H:i', $unix); - $event_day = toGerman(date('l', $unix)); - $event_uid = $event_array['UID']; - $event_url = lowerURL($event_array['URL']); - $event_title = trim($event_array['SUMMARY'], '"'); - $event_descr = trim($event_array['DESCRIPTION'], '"'); - $event_location = trim($event_array['LOCATION'], '"'); - echo "\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - echo "\t\t\n"; - return true; -} - -function printURL(string $url): bool -{ - $stripped = trim($url, '"'); - if ($url != '') - { - echo "
" . $stripped . "\n"; - } - else - { - echo "\n"; - } - return true; + echo("\n"); + echo("\n\n"); } -function grabEvents(ZCiCal $iCalObj): ?array -{ /** - * Läuft durch das iCalendar objekt und sammelt alle Nodes vom Typ - * 'VEVENT' ein. Gibt ein Array mit Objekten vom Typ 'ZCiCalNode' zurück. - * Im Fehlerfall wird Null zurück gegeben. + * Helper function to sort the events chronologically. Compares the first + * entry from the event array (DateTime object). + * + * @param array + * @param array + * @return integer */ - $events = []; - if (isset ($iCalObj->tree->child)) - { - foreach ($iCalObj->tree->child as $node) - { - if ($node->getName() == "VEVENT") - { - $events[] = $node; - } - } - } - else - { - printError("Cant find nodes"); - return null; - } - return $events; +function compareEventStart(array $event_a, array $event_b): int { + // echo("Compare " . $event_a[0] . " and " . $event_b[0] . "\n"); + $a = $event_a[0]; + $b = $event_b[0]; + return $a <=> $b; } -function getEventArray(ZCiCalNode $node): array -{ /** - * Bekommt eine Event Node vom Typ 'ZiCalNode' übergeben und extrahiert - * daraus die gewünschten Elemente. Bildet daraus ein zweidimmensionales - * assoziatives Array. Gibt dieses Array zurück. - * Wird derzeit nur von der tabellarischen Ausgabe referenziert, welche - + momentan nicht genutzt wird. + * Becomes the description string and makes urls contained in this string + * clickable. If anything goes wrong it returns the origin string. + * + * @param string + * @return string */ - /** - * @var ZCiCalNode $node - * @var ZCiCalDataNode $event - */ - $event = $node->data; - $event_array = []; - $keys = array('DTSTART', 'SUMMARY', 'DESCRIPTION', 'URL', 'LOCATION'); - - foreach ($keys as $key) - { - $event_array[$key] = $event[$key]->value[0]; - if ($key === 'DTSTART') - { - if (isset ($event[$key]->parameter['tzid'])) - { - $event_array['TZ'] = $event[$key]->parameter['tzid']; - } - } - else if ($key === 'URL') - { - $event_array[$key] = $event[$key]->parameter['value']; - } +function makeLinks(string $description) { + try { + $reg_pattern = "/(((http|https)\:\/\/)|(www\.))[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,5}(\:[a-zA-Z0-9]+)?(\/\S*)?/"; + return $new = preg_replace($reg_pattern, '$0', $description); + } catch (Throwable $th) { + return $description; } - return $event_array; } -function printError($errMsg) -{ - echo "\n\r

$errMsg

\n\r"; - return true; -} - -function toGerman(string $day): string +/** + * Translates the english weekday names to german. + * + * @param string + * @return string | null + */ +function toGerman(string $day): ?string { switch ($day) { @@ -357,131 +205,91 @@ function toGerman(string $day): string case 'Sunday': return 'Sonntag'; default: - return '?'; + return null; } } -function lowerURL(string $url): string -{ - $old = array('HTTPS', 'HTTP', 'FTP', 'WWW', 'SSH'); - $new = array('https', 'http', 'ftp', 'www', 'ssh'); - $new_url = str_replace($old, $new, $url); - return $new_url; -} -function calculateNextStart(int $unix_start, string $rrule): int -/** - * Berechnet für wiederkehrende Termine den aktuell nächsten Termin. - * dabei werden zur Zeit nur der der Zeitraum zwischen zwei Terminen - * und eine mögliche Anzahl der Termine berücksichtigt. Gibt den neuen - * Termin als Unix-Zeitstempel zurück. - */ -{ - $counter = 0; - - $rule_array = getRuleArray($rrule); - if (isset ($rule_array['COUNT'])) - { - $count = $rule_array['COUNT']; - } - if (isset ($rule_array['FREQ'])) - { - $frequency = $rule_array['FREQ']; - } - if (isset ($rule_array['INTERVAL'])) - { - $interval = $rule_array['INTERVAL']; - } - if (isset ($rule_array['UNTIL'])) - { - //todo implement - $until_string = $rule_array['UNTIL']; - } - - $freq_offset = getOffset($frequency); - if (isset ($interval)) - { - $offset = $freq_offset * $interval; - } - else - { - $offset = $freq_offset; - } - while ($unix_start <= time()) - { - if (isset ($count)) - { - if ($counter >= $count) - { - break; - } - } - $unix_start = $unix_start + $offset; - $counter = $counter + 1; - } - return $unix_start; -} - -function getOffset(string $frequence): int -{ - switch ($frequence) - { - case 'HOURLY': - return 3600; - case 'DAILY': - return 86400; - case 'WEEKLY': - return 604800; - default: - return 1; - } -} - -function getRuleArray(string $rrule): array -/** - * Zerlegt den String einer RRULE und gibt die einzelnen Elemente als - * assoziatives Array zurück. - */ -{ - $rule_array = []; - $rule_strings = explode(';', $rrule); - foreach ($rule_strings as $r_string) - { - $rule = explode('=', $r_string); - $rule_array[$rule[0]] = $rule[1]; - } - return $rule_array; -} - -function EventIsPast(int $unix_start): bool -/** - * Prüft, ob die übergebenen Unixzeit älter als der aktuelle Tag ist. Gibt - * Wahr oder Falsch zurück. - */ -{ - $event_date = date('d.m.Y', $unix_start); - $day_end = strtotime($event_date) + 86400; - $actual_date = time(); - - if ($day_end < $actual_date) - { - return true; - } - return false; -} +/////////////////////////////////////////////////////////////////////////// +/// start des programmes +/////////////////////////////////////////////////////////////////////////// /** - * Bekommt zwei Eventnodes übergeben und vergleicht deren Startdatum. Die - * Funktion wird intern von ausort() benutzt, um das Array mit den Eventnodes - * nach Datum zu sortieren. + * The main function. * - * @param ZCiCalNode $event_a - * @param ZCiCalNode $event_b - * @return int */ -function compareEventStart(ZCiCalNode $event_a, ZCiCalNode $event_b): int -{ - $a = $event_a->data['DTSTART']->value[0]; - $b = $event_b->data['DTSTART']->value[0]; - return $a <=> $b; +function printEventList(): bool { + error_log("getEvents called"); + date_default_timezone_set("Europe/Berlin"); + $today_datetime = new DateTime(); + date_time_set($today_datetime, 0, 0, 0, 0); + $date_helper = new VObject\DateTimeParser(); + $eventlist = []; + $next_events = []; + + // einlesen der kalenderdatei + + $vcalendar = initCalendar(); + if ($vcalendar == null) { + error_log("getEvents unsuccessful terminated"); + return false; + } + + // die events aus dem kalender herausziehen + + $eventlist = grabEvents($vcalendar); + if ($eventlist == null) { + error_log("gabEvent returns null"); + return false; + } + elseif (count($eventlist) == 0) { + echo("\n

Keine Termine gefunden

\n"); + return false; + } + + // durch die liste der events laufen. wir holen uns den starttermin und + // wandeln ihn in ein datetime objekt um. liegt das in der vergangenheit + // und der termin hat eine rrule, holen wir uns einen iterator über die + // rrule (dazu brauchen wir die uid) und versuche den nächsten gültigen + // termin zu bekommen. gibt es einen gültigen termin, wird das event mit + // dem neuen starttermin an die liste der relevanten termine angehängt. + // ist der starttermin von anfang an in der zukunft, dann wird er + // natürlich auch angehängt. + + foreach ($eventlist as $event) { + $next_event = []; + $e_uid = $event->UID; + $e_start = $event->DTSTART; + $e_summary = $event->SUMMARY; + $e_description = $event->DESCRIPTION; + $e_location = $event->LOCATION; + $e_url = $event->URL; + $start_datetime = $date_helper->parseDateTime($e_start); + if ($start_datetime < $today_datetime) { + if (isset($event->RRULE)) { + $rriter = new VObject\RecurrenceIterator($vcalendar, $e_uid); + $start_datetime = getNextDate($rriter, $today_datetime); + if ($start_datetime == null) { + continue; + } else { + array_push($next_events, array($start_datetime, $event)); + } + } + } else { + array_push($next_events, array($start_datetime, $event)); + } + } + + // liste der anstehenden events nach dem begin sortieren + + usort($next_events, "compareEventStart"); + + // die sortierte liste ausgeben + + foreach ($next_events as $event) { + printEvent($event, $date_helper); + } + error_log("getEvents successful terminated"); + return true; } +
DatumWochentagZeitOrtTitelBeschreibung
" . $event_date . "" . $event_day . "" . $event_time . " Uhr" . $event_location . "" . $event_title . "" . $event_descr; - printURL($event_url); - echo "\t