Compare commits

..

No commits in common. "45ca1c4c48abf6309a5fbfefd3335c9f7330d362" and "9f455202b371de36ec9ab2a2301c0b2d4f02b32e" have entirely different histories.

10 changed files with 112 additions and 304 deletions

View file

@ -6,8 +6,8 @@
"source": {
"kind": "ics_feed",
"data": {
"url": "https://www.phpclasses.org/browse/download/1/file/63438/name/example.ics",
"combine": true
"url": "https://export.kalender.digital/ics/0/3e10dae66950379d4cc8/gesamterkalender.ics?past_months=1&future_months=2",
"condense": false
}
},
"settings": {

View file

@ -12,16 +12,6 @@ class struct_auth
}
/**
*/
class struct_source_data_ics_feed
{
public string $url;
public bool $combined;
public int $lifetime;
}
/**
*/
class struct_source
@ -101,14 +91,7 @@ function load(
function get(
) : struct_root
{
if (_state::$data === null)
{
throw (new \Exception('not yet loaded'));
}
else
{
return _state::$data;
}
return _state::$data;
}
?>

View file

@ -170,6 +170,7 @@ class class_cache_memory
}
/**
*/
class class_cache_file

View file

@ -296,7 +296,7 @@ function time_decode(
\intval(\substr($time_encoded, 0, 2)),
\intval(\substr($time_encoded, 2, 2)),
\intval(\substr($time_encoded, 4, 2)),
((\strlen($time_encoded) >= 7) && ($time_encoded[6] === 'Z'))
((\strlen($time_encoded >= 7) && ($time_encoded[6] === 'Z')))
));
}
@ -496,7 +496,7 @@ function vcalendar_decode(
fn($x) => \explode(',', $x),
\array_values(
\array_filter(
($event_raw->additionalProperties['categories_array'] ?? []),
$event_raw->additionalProperties['categories_array'],
fn($x) => \is_string($x)
)
)

View file

@ -1,119 +0,0 @@
<?php
namespace davigil\model;
/**
*/
class struct_event
{
public string $id;
public string $title;
public /*type_unix_timestamp*/int $begin;
public /*type_unix_timestamp*/?int $end;
public ?string $location;
public ?string $description;
public array $tags;
public function __construct(
string $id,
string $title,
/*type_unix_timestamp*/int $begin,
/*type_unix_timestamp*/?int $end,
?string $location,
?string $description,
array $tags
)
{
$this->id = $id;
$this->title = $title;
$this->begin = $begin;
$this->end = $end;
$this->location = $location;
$this->description = $description;
$this->tags = $tags;
}
}
/**
*/
function event_to_raw(
struct_event $event
)
{
return [
'id' => $event->id,
'title' => $event->title,
'begin' => $event->begin,
'end' => $event->end,
'location' => $event->location,
'description' => $event->description,
'tags' => $event->tags,
];
}
/**
*/
function event_from_raw(
$event_raw
) : struct_event
{
return (new struct_event(
$event_raw['id'],
$event_raw['title'],
$event_raw['begin'],
$event_raw['end'],
$event_raw['location'],
$event_raw['description'],
$event_raw['tags'],
));
}
/**
*/
class struct_calendar
{
public array $events;
public function __construct(
array $events
)
{
$this->events = $events;
}
}
/**
*/
function calendar_to_raw(
struct_calendar $calendar
)
{
return [
'events' => \array_map(
fn($event) => event_to_raw($event),
$calendar->events
),
];
}
/**
*/
function calendar_from_raw(
$calendar_raw
) : struct_calendar
{
return (new struct_calendar(
\array_map(
fn($event_raw) => event_from_raw($event_raw),
$calendar_raw['events']
)
));
}
?>

View file

@ -5,7 +5,6 @@ namespace davigil\overwrites;
require_once('vendor/autoload.php');
require_once('helpers/call.php');
require_once('helpers/ics.php');
require_once('model.php');
require_once('sources/_interface.php');
require_once('conf.php');
@ -70,32 +69,32 @@ class class_caldav_backend
* @todo outsource
*/
private function event_to_vevent(
\davigil\model\struct_event $event
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->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)
\davigil\helpers\ics\datetime_from_unix_timestamp($event['begin'])
);
$vevent->dtend = (
($event->end === null)
($event['end'] === null)
?
null
:
new \davigil\helpers\ics\struct_dt(
'',
\davigil\helpers\ics\datetime_from_unix_timestamp($event->end)
\davigil\helpers\ics\datetime_from_unix_timestamp($event['end'])
)
);
$vevent->summary = $event->title;
$vevent->location = $event->location;
$vevent->description = $event->description;
$vevent->summary = $event['title'];
$vevent->location = $event['location'];
$vevent->description = $event['description'];
$vevent->class = \davigil\helpers\ics\enum_class::public_;
$vevent->categories = $event->tags;
$vevent->categories = $event['tags'];
}
return $vevent;
}
@ -132,11 +131,11 @@ class class_caldav_backend
$principalUri
)
{
$calendar = $this->source->get([]);
$data = $this->source->get([]);
$tags = [];
foreach ($calendar->events as $event)
foreach ($data as $entry)
{
foreach ($event->tags as $tag)
foreach ($entry['tags'] as $tag)
{
$tags[$tag] = null;
}
@ -188,27 +187,27 @@ class class_caldav_backend
)
{
$tag = $calendarId;
$calendar = $this->source->get([]);
$data = $this->source->get([]);
$result = \array_map(
fn($event) => [
fn($entry) => [
'calendarid' => $calendarId,
'id' => $event->id,
'id' => $entry['id'],
// 'uri' => \sprintf('%s.ics', $entry['id']),
'uri' => $event->id,
'uri' => $entry['id'],
'lastmodified' => \time(),
// 'etag' => null,
// 'size' => null,
'component' => 'vevent',
'{DAV:}displayname' => $event->title,
'{DAV:}displayname' => $entry['title'],
],
\array_values(
\array_filter(
$calendar->events,
fn($event) => \in_array(
$data,
fn($entry) => \in_array(
$tag,
\array_map(
fn($x) => $this->hash_tag($x),
$event->tags
$entry['tags']
)
)
)
@ -231,21 +230,18 @@ class class_caldav_backend
$entries = \array_values(
\array_filter(
$data,
fn($entry) => ($entry->id === $id)
fn($entry) => ($entry['id'] === $id)
)
);
if (\count($entries) < 1)
if (\count($entries) !== 1)
{
throw (new \Exception(\sprintf('not found: %s', $objectUri)));
}
else if (\count($entries) > 1)
{
throw (new \Exception(\sprintf('ambiguous: %s', $objectUri)));
throw (new \Exception(\sprintf('not found or ambiguous')));
}
else
{
$vcalendar = $this->events_to_vcalendar($entries);
$ics = \davigil\helpers\ics\vcalendar_encode($vcalendar);
\error_log($ics);
return [
'calendardata' => $ics,
'uri' => $objectUri,

View file

@ -21,24 +21,14 @@ function make(
{
case 'ics_feed':
{
return (
new class_source_ics_feed(
$descriptor['data']['url'],
($descriptor['data']['lifetime'] ?? (60 * 15)),
($descriptor['data']['combine'] ?? false)
)
);
return (new class_source_ics_feed(
$descriptor['data']['url'],
($descriptor['data']['condense'] ?? false)
));
}
default:
{
throw (
new \Exception(
\sprintf(
'unhandled source kind: %s',
$descriptor['kind']
)
)
);
throw (new \Exception(\sprintf('unhandled source kind: %s', $descriptor['kind'])));
break;
}
}

View file

@ -15,10 +15,23 @@ interface interface_source
* password:(null|string),
* >
* }
* @return array {
* list<
* record<
* id:string,
* title:string,
* begin:type_unix_timestamp,
* end:(null|type_unix_timestamp),
* location:(null|string),
* description:(null|string),
* tags:list<string>,
* >
* >
* }
*/
public function get(
array $parameters
) : \davigil\model\struct_calendar
) : array
;
}

View file

@ -6,7 +6,6 @@ require_once('helpers/string.php');
require_once('helpers/cache.php');
require_once('helpers/pit.php');
require_once('helpers/ics.php');
require_once('model.php');
/**
@ -22,107 +21,31 @@ class class_source_ics_feed
/**
*/
private ?int $lifetime;
/**
*/
private bool $combine;
private bool $condense;
/**
*/
public function __construct(
string $url,
?int $lifetime,
bool $combine
bool $condense
)
{
$this->url = $url;
$this->lifetime = $lifetime;
$this->combine = $combine;
$this->cache_file = \davigil\helpers\call\convey(
$this->condense = $condense;
$this->cache_file = new \davigil\helpers\cache\class_cache_encoded(
new \davigil\helpers\cache\class_cache_file('data'),
[
fn($x) => new \davigil\helpers\cache\class_cache_encoded(
$x,
fn($value) => \json_encode($value),
fn($value_encoded) => \json_decode($value_encoded, true)
),
]
);
$this->cache_memory = \davigil\helpers\call\convey(
(new \davigil\helpers\cache\class_cache_memory()),
[
]
);
}
/**
*/
private function vcalendar_to_calendar(
\davigil\helpers\ics\struct_vcalendar $vcalendar
) : \davigil\model\struct_calendar
{
return (
new \davigil\model\struct_calendar(
\array_map(
fn($vevent) => (new \davigil\model\struct_event(
// id
$vevent->uid,
// title
(
$this->combine
?
\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)
?
null
:
\davigil\helpers\ics\datetime_to_unix_timestamp($vevent->dtend->value)
),
// location
$vevent->location,
// description
$vevent->description,
// 'tags
(
$this->combine
?
['combined']
:
$vevent->categories
)
)),
$vcalendar->events
)
)
fn($value) => \json_encode($value),
fn($value_encoded) => \json_decode($value_encoded, true)
);
$this->cache_memory = new \davigil\helpers\cache\class_cache_memory();
}
/**
*/
private function retrieve(
)
) : array
{
$client = new \Sabre\HTTP\Client();
$request = new \Sabre\HTTP\Request(
@ -139,21 +62,52 @@ class class_source_ics_feed
{
$ics = $response->getBody();
$vcalendar = \davigil\helpers\ics\vcalendar_decode($ics);
$calendar = $this->vcalendar_to_calendar($vcalendar);
$calendar_raw = \davigil\model\calendar_to_raw($calendar);
return $calendar_raw;
$data = \array_map(
fn($vevent) => [
'id' => $vevent->uid,
'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)
?
null
:
\davigil\helpers\ics\datetime_to_unix_timestamp($vevent->dtend->value)
),
'location' => $vevent->location,
'description' => $vevent->description,
'tags' => (
$this->condense
?
['dummy']
:
$vevent->categories
),
],
$vcalendar->events
);
return $data;
break;
}
default:
{
throw (
new \Exception(
\sprintf(
'unhandled response status code: %u',
$status_code
)
)
);
throw (new \Exception(\sprintf('unhandled response status code: %u', $status_code)));
break;
}
}
@ -165,29 +119,24 @@ class class_source_ics_feed
*/
public function get(
array $parameters
) : \davigil\model\struct_calendar
) : array
{
$key = $this->url;
$f1 = fn() => $this->retrieve();
$f2 = fn() => \davigil\helpers\cache\get(
$this->cache_file,
$key,
$f1,
[
'ttl' => $this->lifetime,
]
);
$f3 = fn() => \davigil\helpers\cache\get(
return \davigil\helpers\cache\get(
$this->cache_memory,
$key,
$f2,
fn() => \davigil\helpers\cache\get(
$this->cache_file,
$key,
fn() => $this->retrieve(),
[
'ttl' => (60 * 5),
]
),
[
'ttl' => null,
]
);
return \davigil\model\calendar_from_raw(
($f3)()
);
}
}

View file

@ -7,12 +7,6 @@ dir_source=source
dir_build=build
name=index.php
## args
if [ $# -ge 1 ] ; then profile=$1 && shift ; else profile="" ; fi
## exec
mkdir -p ${dir_build}
@ -25,4 +19,5 @@ rm -f ${dir_build}/${name}
cp -r -u -v ${dir_source}/* ${dir_build}/
ln -s main.php ${dir_build}/index.php
test -z ${profile} || cp conf/${profile}.json ${dir_build}/conf.json
cp conf/example.json ${dir_build}/conf.json