} */ private array $sources; /** */ private ?string $selected_source_name; /** */ public function __construct( array $sources ) { // parent::__construct(); $this->sources = $sources; $this->selected_source_name = null; } /** * @todo outsource */ private function event_to_vevent( \davina\model\struct_event $event ) : \davina\helpers\ics\struct_vevent { $vevent = new \davina\helpers\ics\struct_vevent(); { $vevent->uid = $event->id; $vevent->dtstamp = \davina\helpers\ics\datetime_from_unix_timestamp($event->begin); $vevent->dtstart = new \davina\helpers\ics\struct_dt( '', \davina\helpers\ics\datetime_from_unix_timestamp($event->begin) ); $vevent->dtend = ( ($event->end === null) ? null : new \davina\helpers\ics\struct_dt( '', \davina\helpers\ics\datetime_from_unix_timestamp($event->end) ) ); $vevent->summary = $event->title; $vevent->location = $event->location; $vevent->description = $event->description; $vevent->class = \davina\helpers\ics\enum_class::public_; $vevent->categories = $event->tags; } return $vevent; } /** * @todo outsource */ private function events_to_vcalendar( array $events ) : \davina\helpers\ics\struct_vcalendar { $vcalendar = new \davina\helpers\ics\struct_vcalendar(); { $vcalendar->version = '2.0'; /** * @todo conf */ $vcalendar->prodid = 'davina'; $vcalendar->method = 'PUBLISH'; $vcalendar->events = \array_map( fn($event) => $this->event_to_vevent($event), $events ); } return $vcalendar; } /** */ private function encode_tag( string $tag ) : string { return \davina\helpers\call\convey( $tag, [ fn($x) => \strtolower($x), fn($x) => \preg_replace('/ä/', 'ae', $x), fn($x) => \preg_replace('/ö/', 'oe', $x), fn($x) => \preg_replace('/ü/', 'ue', $x), fn($x) => \preg_replace('/ß/', 'sz', $x), fn($x) => \preg_replace('/\-/', '', $x), fn($x) => \preg_replace('/ /', '-', $x), fn($x) => \preg_replace('/[^a-zA-Z0-9_\-]/s', '_', $x), ] ); } /** * @param array $parameters { * record< * source_name:string, * calendar_name:string, * > * } */ private function encode_calendar_identifier( array $parameters ) : string { return \sprintf( '%s-%s', $parameters['source_name'], $parameters['calendar_name'] ); } /** * @return array { * record< * source_name:string, * calendar_name:string, * > * } */ private function decode_calendar_identifier( string $str ) : array { $parts = \explode('-', $str, 2); return [ 'source_name' => $parts[0], 'calendar_name' => $parts[1], ]; } /** */ private function get_source( $source_name ) : \davina\sources\interface_source { if ( ($this->selected_source_name === null) || ($this->selected_source_name === $source_name) ) { $this->selected_source_name = $source_name; if (! \array_key_exists($source_name, $this->sources)) { throw (new \Exception(\sprintf('no such source: %s', $source_name))); } else { return $this->sources[$source_name]; } } else { throw (new \Exception('may not change source')); } } /** * [implementation] */ public function getCalendarsForUser( $principalUri ) { // $source = $this->source; $source_name = \explode('/', $principalUri)[1]; $source = $this->get_source($source_name); $calendar = $source->read([]); $tags = []; foreach ($calendar->events as $event) { foreach ($event->tags as $tag) { $tags[$tag] = null; } } $result = \array_map( fn($tag) => [ 'id' => $this->encode_calendar_identifier( [ 'source_name' => $source_name, 'calendar_name' => $this->encode_tag($tag), ] ), 'uri' => $this->encode_tag($tag), 'principaluri' => $principalUri, '{DAV:}displayname' => $tag, \sprintf('{%s}supported-calendar-component-set', \Sabre\CalDAV\Plugin::NS_CALDAV) => new \Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet(['VEVENT']), ], \array_keys($tags) ); // \error_log(\json_encode($result, \JSON_PRETTY_PRINT)); return $result; } /** * [implementation] */ public function createCalendar( $principalUri, $calendarUri, array $properties ) { throw (new \Exception('not implemented: createCalendar')); } /** * [implementation] */ public function deleteCalendar( $calendarId ) { throw (new \Exception('not implemented: deleteCalendar')); } /** * [implementation] */ public function getCalendarObjects( $calendarId ) { $calendar_identifier = $this->decode_calendar_identifier($calendarId); $source_name = $calendar_identifier['source_name']; $source = $this->get_source($source_name); $tag = $calendar_identifier['calendar_name']; $calendar = $source->read([]); $result = \array_map( fn($event) => [ 'calendarid' => $calendarId, 'id' => $event->id, // 'uri' => \sprintf('%s.ics', $entry['id']), 'uri' => $event->id, 'lastmodified' => \time(), // 'etag' => null, // 'size' => null, 'component' => 'vevent', '{DAV:}displayname' => $event->title, ], \array_values( \array_filter( $calendar->events, fn($event) => \in_array( $tag, \array_map( fn($x) => $this->encode_tag($x), $event->tags ) ) ) ) ); return $result; } /** * [implementation] */ public function getCalendarObject( $calendarId, $objectUri ) { $id = $objectUri; $calendar_identifier = $this->decode_calendar_identifier($calendarId); $source_name = $calendar_identifier['source_name']; $source = $this->get_source($source_name); $tag = $calendar_identifier['calendar_name']; $calendar = $source->read([]); $events = \array_values( \array_filter( $calendar->events, fn($event) => ($event->id === $id) ) ); if (\count($events) < 1) { throw (new \Exception(\sprintf('not found: %s', $objectUri))); } else if (\count($events) > 1) { throw (new \Exception(\sprintf('ambiguous: %s', $objectUri))); } else { $vcalendar = $this->events_to_vcalendar($events); $ics = \davina\helpers\ics\vcalendar_encode($vcalendar); return [ 'calendardata' => $ics, 'uri' => $objectUri, /** * @todo */ 'lastmodified' => \time(), /** * @todo */ // 'etag' => '""', /** * @todo */ // 'size' => 1, 'component' => 'vcalendar', ]; } } /** * [implementation] */ public function createCalendarObject( $calendarId, $objectUri, $calendarData ) { throw (new \Exception('not implemented: createCalendarObject')); } /** * [implementation] */ public function updateCalendarObject( $calendarId, $objectUri, $calendarData ) { throw (new \Exception('not implemented: updateCalendarObject')); } /** * [implementation] */ public function deleteCalendarObject( $calendarId, $objectUri ) { throw (new \Exception('not implemented: deleteCalendarObject')); } } ?>