calendar = new CalendarInfo(); $this->baseUrl = rtrim($cfg['base_url'] ?? '', '/') . '/'; $this->userName = $cfg['username'] ?? ''; $this->calendar->displayName = $cfg['calendar_name'] ?? ''; if ( empty($this->baseUrl) || empty($this->userName) || empty($cfg['password'] ?? '') || empty($this->calendar->displayName) ) { Log::warning('CalDAV config incomplete', ['base' => $this->baseUrl, 'calendarName' => $this->calendar->displayName, 'userName' => $this->userName]); } $this->client = new Client([ 'baseUri' => $this->baseUrl, 'userName' => $cfg['username'] ?? null, 'password' => $cfg['password'] ?? null, 'authType' => \Sabre\DAV\Client::AUTH_BASIC, 'userAgent' => $cfg['user_agent'] ?? 'caldav-client', ]); $this->getCalendarInfo(); } /** * Requests all calendars of the user and gets the ID that belongs to the calendar name */ public function getCalendarId() { $response = $this->client->propFind( 'calendars/' . $this->userName . '/', [ '{DAV:}resourcetype', '{DAV:}displayname', ], 1 ); foreach ($response as $href => $node) { if (array_key_exists('{DAV:}displayname', $node) && strcasecmp($node['{DAV:}displayname'], $this->calendar->displayName) == 0) { $this->calendar->url = $href; $parts = explode('/', trim($href, '/')); return array_pop($parts); } } } /** * Request information about the calendar (ctag, sync-token, color) */ public function getCalendarInfo() { $this->calendar->id = $this->getCalendarId(); $response = $this->client->propFind( 'calendars/' . $this->userName . '/' . $this->calendar->id, [ '{DAV:}displayname', '{http://calendarserver.org/ns/}getctag', '{DAV:}sync-token', '{http://apple.com/ns/ical/}calendar-color', ] ); // TODO: store ctag to compare whether the calendar has changed $this->calendar->ctag = $response['{http://calendarserver.org/ns/}getctag']; $this->calendar->syncToken = $response['{DAV:}sync-token']; $this->calendar->color = $response['{http://apple.com/ns/ical/}calendar-color']; return $this->calendar; } public function getTodos() { $body = '' . ' ' . ' ' . ' ' . ' ' . ' ' . ' ' . ' ' . ' ' . ' ' . ''; $headers = [ 'Depth' => '1', 'Content-Type' => 'application/xml; charset=utf-8', 'Prefer' => 'return-minimal' ]; $response = $this->client->request( 'REPORT', 'calendars/' . $this->userName . '/' . $this->calendar->id, $body, $headers ); // Sabre\DAV\Xml\Service $service = new Service(); // Sabre\DAV\Xml\Response\MultiStatus $multiStatus = $service->parse($response['body']); // Sabre\DAV\Xml\Element\Response $responses = $multiStatus->getResponses(); $todos = []; foreach ($responses as $key => $response) { $href = $response->getHref(); $properties = $response->getResponseProperties(); $calendarData = $properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']; $etag = $properties[200]['{DAV:}getetag']; $vcalendar = VObject\Reader::read($calendarData); // Create new todo $todo = new Todo(); // Map VTODO -> App\Model\Todo $todo->id = isset($vcalendar->VTODO->UID) ? $vcalendar->VTODO->UID->getValue() : uniqid(); $todo->etag = $etag; $todo->title = isset($vcalendar->VTODO->SUMMARY) ? $vcalendar->VTODO->SUMMARY->getValue() : 'Neues Todo'; if (isset($vcalendar->VTODO->DESCRIPTION)) $todo->description = $vcalendar->VTODO->DESCRIPTION->getValue(); $todo->type_id = 2; $todo->url = $href; if (isset($vcalendar->VTODO->DUE)) $todo->due_date = $vcalendar->VTODO->DUE->getDateTime(); if(isset($vcalendar->VTODO->RRULE)) $todo->recurring = $vcalendar->VTODO->RRULE->getValue(); if(isset($vcalendar->VTODO->PRIORITY)) $todo->priority = $vcalendar->VTODO->PRIORITY->getValue(); if(isset($vcalendar->VTODO->STATUS)) $todo->status = $vcalendar->VTODO->STATUS->getValue(); if(isset($vcalendar->VTODO->{'RELATED-TO'})) $todo->parent = $vcalendar->VTODO->{'RELATED-TO'}->getValue(); $todo->created_at = $vcalendar->VTODO->CREATED->getDateTime(); $todo->last_modified = $vcalendar->VTODO->{'LAST-MODIFIED'}->getDateTime(); $todos[] = $todo; } return $todos; } }