This commit is contained in:
fenris 2025-09-09 17:43:23 +00:00
parent 6033cea60e
commit 9f455202b3
7 changed files with 202 additions and 72 deletions

View file

@ -6,8 +6,12 @@
"source": {
"kind": "ics_feed",
"data": {
"url": "https://export.kalender.digital/ics/0/3e10dae66950379d4cc8/gesamterkalender.ics?past_months=1&future_months=2"
"url": "https://export.kalender.digital/ics/0/3e10dae66950379d4cc8/gesamterkalender.ics?past_months=1&future_months=2",
"condense": false
}
},
"settings": {
"timezone": "UTC"
}
}

View file

@ -3,11 +3,47 @@
namespace davigil\conf;
/**
*/
class struct_auth
{
public string $kind;
public $data;
}
/**
*/
class struct_source
{
public string $kind;
public $data;
}
/**
*/
class struct_settings
{
public string $timezone;
}
/**
*/
class struct_root
{
public struct_auth $auth;
public struct_source $source;
public struct_settings $settings;
}
/**
*/
class _state
{
public static $data = null;
public static ?struct_root $data = null;
}
@ -17,19 +53,43 @@ function load(
string $path
) : void
{
_state::$data = \json_decode(
$data_raw = \json_decode(
\file_get_contents(
$path
),
true
);
{
$data = new struct_root();
// auth
{
$auth = new struct_auth();
$auth->kind = (($data_raw['auth'] ?? [])['kind'] ?? 'none');
$auth->data = (($data_raw['auth'] ?? [])['data'] ?? null);
$data->auth = $auth;
}
// source
{
$source = new struct_source();
$source->kind = $data_raw['source']['kind'];
$source->data = ($data_raw['source']['data'] ?? null);
$data->source = $source;
}
// settings
{
$settings = new struct_settings();
$settings->timezone = (($data_raw['settings'] ?? [])['timezone'] ?? 'UTC');
$data->settings = $settings;
}
_state::$data = $data;
}
}
/**
*/
function get(
)
) : struct_root
{
return _state::$data;
}

View file

@ -709,6 +709,24 @@ function vcalendar_encode(
);
}
*/
// categories
if (
($vevent->categories !== null)
&&
(\count($vevent->categories) > 0)
)
{
\array_push(
$content_lines,
\davigil\helpers\string_\coin(
'CATEGORIES:{{categories}}',
[
'categories' => \implode(',', $vevent->categories),
]
)
);
}
}
\array_push($content_lines, 'END:VEVENT');
}

View file

@ -7,6 +7,7 @@ require_once('overwrites/principal_backend.php');
require_once('overwrites/auths/_factory.php');
require_once('overwrites/caldav_backend.php');
require_once('sources/_factory.php');
require_once('conf.php');
function main(
@ -14,10 +15,14 @@ function main(
{
\davigil\conf\load('conf.json');
// \date_default_timezone_set('Europe/Berlin');
\date_default_timezone_set('UTC');
\date_default_timezone_set(\davigil\conf\get()->settings->timezone);
$source = \davigil\sources\make(\davigil\conf\get()['source']);
$source = \davigil\sources\make(
[
'kind' => \davigil\conf\get()->source->kind,
'data' => \davigil\conf\get()->source->data,
]
);
$principal_backend = new \davigil\overwrites\class_principle_backend();
@ -34,14 +39,17 @@ function main(
new \Sabre\DAV\Auth\Plugin(
\davigil\overwrites\make_auth_backend(
$source,
\davigil\conf\get()['auth']
[
'kind' => \davigil\conf\get()->auth->kind,
'data' => \davigil\conf\get()->auth->data,
]
)
)
);
/**
* this breaks authentication
* this somehow breaks authentication, but seems to be required for calendar discovery
*/
// $server->addPlugin(new \Sabre\DAVACL\Plugin());
$server->addPlugin(new \Sabre\DAVACL\Plugin());
$server->addPlugin(new \Sabre\CalDAV\Plugin());
$server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());

View file

@ -63,9 +63,69 @@ class class_caldav_backend
]
);
}
/**
* @todo outsource
*/
private function event_to_vevent(
array $event
) : \davigil\helpers\ics\struct_vevent
{
$vevent = new \davigil\helpers\ics\struct_vevent();
{
$vevent->uid = $event['id'];
$vevent->dtstamp = \davigil\helpers\ics\datetime_from_unix_timestamp($event['begin']);
$vevent->dtstart = new \davigil\helpers\ics\struct_dt(
'',
\davigil\helpers\ics\datetime_from_unix_timestamp($event['begin'])
);
$vevent->dtend = (
($event['end'] === null)
?
null
:
new \davigil\helpers\ics\struct_dt(
'',
\davigil\helpers\ics\datetime_from_unix_timestamp($event['end'])
)
);
$vevent->summary = $event['title'];
$vevent->location = $event['location'];
$vevent->description = $event['description'];
$vevent->class = \davigil\helpers\ics\enum_class::public_;
$vevent->categories = $event['tags'];
}
return $vevent;
}
/**
* @todo outsource
*/
private function events_to_vcalendar(
array $events
) : \davigil\helpers\ics\struct_vcalendar
{
$vcalendar = new \davigil\helpers\ics\struct_vcalendar();
{
$vcalendar->version = '2.0';
/**
* @todo conf
*/
$vcalendar->prodid = 'davigil';
$vcalendar->method = 'PUBLISH';
$vcalendar->events = \array_map(
fn($event) => $this->event_to_vevent($event),
$events
);
}
return $vcalendar;
}
/**
* [implementation]
*/
public function getCalendarsForUser(
$principalUri
@ -96,6 +156,7 @@ class class_caldav_backend
/**
* [implementation]
*/
public function createCalendar(
$principalUri,
@ -108,6 +169,7 @@ class class_caldav_backend
/**
* [implementation]
*/
public function deleteCalendar(
$calendarId
@ -118,6 +180,7 @@ class class_caldav_backend
/**
* [implementation]
*/
public function getCalendarObjects(
$calendarId
@ -155,64 +218,7 @@ class class_caldav_backend
/**
* @todo outsource
*/
private function event_to_vevent(
array $event
) : \davigil\helpers\ics\struct_vevent
{
$vevent = new \davigil\helpers\ics\struct_vevent();
{
$vevent->uid = $event['id'];
$vevent->dtstamp = \davigil\helpers\ics\datetime_from_unix_timestamp($event['begin']);
$vevent->dtstart = new \davigil\helpers\ics\struct_dt(
'',
\davigil\helpers\ics\datetime_from_unix_timestamp($event['begin'])
);
$vevent->dtend = (
($event['end'] === null)
?
null
:
new \davigil\helpers\ics\struct_dt(
'',
\davigil\helpers\ics\datetime_from_unix_timestamp($event['end'])
)
);
$vevent->summary = $event['title'];
$vevent->location = $event['location'];
$vevent->description = $event['description'];
$vevent->class = \davigil\helpers\ics\enum_class::public_;
}
return $vevent;
}
/**
* @todo outsource
*/
private function events_to_vcalendar(
array $events
) : \davigil\helpers\ics\struct_vcalendar
{
$vcalendar = new \davigil\helpers\ics\struct_vcalendar();
{
$vcalendar->version = '2.0';
/**
* @todo conf
*/
$vcalendar->prodid = 'davigil';
$vcalendar->method = 'PUBLISH';
$vcalendar->events = \array_map(
fn($event) => $this->event_to_vevent($event),
$events
);
}
return $vcalendar;
}
/**
* [implementation]
*/
public function getCalendarObject(
$calendarId,
@ -235,6 +241,7 @@ class class_caldav_backend
{
$vcalendar = $this->events_to_vcalendar($entries);
$ics = \davigil\helpers\ics\vcalendar_encode($vcalendar);
\error_log($ics);
return [
'calendardata' => $ics,
'uri' => $objectUri,
@ -257,6 +264,7 @@ class class_caldav_backend
/**
* [implementation]
*/
public function createCalendarObject(
$calendarId,
@ -269,6 +277,7 @@ class class_caldav_backend
/**
* [implementation]
*/
public function updateCalendarObject(
$calendarId,
@ -281,6 +290,7 @@ class class_caldav_backend
/**
* [implementation]
*/
public function deleteCalendarObject(
$calendarId,

View file

@ -22,7 +22,8 @@ function make(
case 'ics_feed':
{
return (new class_source_ics_feed(
$descriptor['data']['url']
$descriptor['data']['url'],
($descriptor['data']['condense'] ?? false)
));
}
default:

View file

@ -19,13 +19,20 @@ class class_source_ics_feed
private string $url;
/**
*/
private bool $condense;
/**
*/
public function __construct(
string $url
string $url,
bool $condense
)
{
$this->url = $url;
$this->condense = $condense;
$this->cache_file = new \davigil\helpers\cache\class_cache_encoded(
new \davigil\helpers\cache\class_cache_file('data'),
fn($value) => \json_encode($value),
@ -58,7 +65,23 @@ class class_source_ics_feed
$data = \array_map(
fn($vevent) => [
'id' => $vevent->uid,
'title' => $vevent->summary,
'title' => (
$this->condense
?
\sprintf(
'%s%s',
$vevent->summary,
\implode(
'',
\array_map(
fn($category) => \sprintf(' (%s)', $category),
$vevent->categories
)
)
)
:
$vevent->summary
),
'begin' => \davigil\helpers\ics\datetime_to_unix_timestamp($vevent->dtstart->value),
'end' => (
($vevent->dtend === null)
@ -69,7 +92,13 @@ class class_source_ics_feed
),
'location' => $vevent->location,
'description' => $vevent->description,
'tags' => $vevent->categories,
'tags' => (
$this->condense
?
['dummy']
:
$vevent->categories
),
],
$vcalendar->events
);