core/source/sources/ics_feed.php

261 lines
5 KiB
PHP
Raw Normal View History

2025-09-09 12:07:53 +02:00
<?php
2025-09-22 23:17:08 +02:00
/*
davina Calendar data CalDAV conditioner
Copyright (C) 2025 Fenris <fenris@folksprak.org>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
2025-09-09 12:07:53 +02:00
2025-09-16 12:05:35 +02:00
namespace davina\sources;
2025-09-09 12:07:53 +02:00
2025-09-16 12:48:45 +02:00
require_once(DIR_LOGIC . '/helpers/string.php');
require_once(DIR_LOGIC . '/helpers/cache.php');
require_once(DIR_LOGIC . '/helpers/pit.php');
require_once(DIR_LOGIC . '/helpers/ics.php');
require_once(DIR_LOGIC . '/base.php');
2025-09-21 18:49:03 +02:00
require_once(DIR_LOGIC . '/sources/_interface.php');
2025-09-16 12:48:45 +02:00
require_once(DIR_LOGIC . '/model.php');
2025-09-09 12:07:53 +02:00
/**
*/
class class_source_ics_feed
implements interface_source
{
/**
*/
2025-09-10 15:03:44 +02:00
private string $url_template;
2025-09-09 12:07:53 +02:00
2025-09-09 19:43:23 +02:00
/**
*/
2025-09-09 23:17:19 +02:00
private ?int $lifetime;
/**
*/
2025-09-21 18:49:03 +02:00
private bool $conflate;
2025-09-09 19:43:23 +02:00
2025-09-09 12:07:53 +02:00
/**
*/
public function __construct(
2025-09-10 15:03:44 +02:00
string $url_template,
2025-09-09 23:17:19 +02:00
?int $lifetime,
2025-09-21 18:49:03 +02:00
bool $conflate
2025-09-09 12:07:53 +02:00
)
{
2025-09-10 15:03:44 +02:00
$this->url_template = $url_template;
2025-09-09 23:17:19 +02:00
$this->lifetime = $lifetime;
2025-09-21 18:49:03 +02:00
$this->conflate = $conflate;
2025-09-16 12:05:35 +02:00
$this->cache_file = \davina\helpers\call\convey(
new \davina\helpers\cache\class_cache_file('data'),
2025-09-09 23:17:19 +02:00
[
2025-09-16 12:05:35 +02:00
fn($x) => new \davina\helpers\cache\class_cache_encoded(
2025-09-09 23:17:19 +02:00
$x,
fn($value) => \json_encode($value),
fn($value_encoded) => \json_decode($value_encoded, true)
),
]
);
2025-09-16 12:05:35 +02:00
$this->cache_memory = \davina\helpers\call\convey(
(new \davina\helpers\cache\class_cache_memory()),
2025-09-09 23:17:19 +02:00
[
]
2025-09-09 12:07:53 +02:00
);
}
2025-09-10 15:03:44 +02:00
/**
*/
private function url(
$parameters
) : string
{
2025-09-16 12:05:35 +02:00
return \davina\helpers\string_\coin(
2025-09-10 15:03:44 +02:00
$this->url_template,
2025-09-21 18:49:03 +02:00
[
'username' => ($parameters['auth_username'] ?? null),
'password' => ($parameters['auth_password'] ?? null),
]
2025-09-10 15:03:44 +02:00
);
}
2025-09-09 12:07:53 +02:00
/**
*/
2025-09-09 23:17:19 +02:00
private function vcalendar_to_calendar(
2025-09-21 18:49:03 +02:00
\davina\helpers\ics\struct_vcalendar $vcalendar,
?string $realm_name
2025-09-16 12:05:35 +02:00
) : \davina\model\struct_calendar
2025-09-09 12:07:53 +02:00
{
2025-09-09 23:17:19 +02:00
return (
2025-09-16 12:05:35 +02:00
new \davina\model\struct_calendar(
2025-09-09 23:17:19 +02:00
\array_map(
2025-09-16 12:05:35 +02:00
fn($vevent) => (new \davina\model\struct_event(
2025-09-09 23:17:19 +02:00
// id
$vevent->uid,
// title
(
2025-09-21 18:49:03 +02:00
(! $this->conflate)
2025-09-09 19:43:23 +02:00
?
2025-09-21 18:49:03 +02:00
$vevent->summary
:
2025-09-09 19:43:23 +02:00
\sprintf(
'%s%s',
$vevent->summary,
\implode(
'',
\array_map(
fn($category) => \sprintf(' (%s)', $category),
$vevent->categories
)
)
)
),
2025-09-09 23:17:19 +02:00
// begin
2025-09-16 12:05:35 +02:00
\davina\helpers\ics\datetime_to_unix_timestamp($vevent->dtstart->value),
2025-09-09 23:17:19 +02:00
// end
(
2025-09-09 12:07:53 +02:00
($vevent->dtend === null)
?
null
:
2025-09-16 12:05:35 +02:00
\davina\helpers\ics\datetime_to_unix_timestamp($vevent->dtend->value)
2025-09-09 12:07:53 +02:00
),
2025-09-09 23:17:19 +02:00
// location
$vevent->location,
// description
$vevent->description,
// 'tags
(
2025-09-21 18:49:03 +02:00
(! $this->conflate)
2025-09-09 19:43:23 +02:00
?
$vevent->categories
2025-09-21 18:49:03 +02:00
:
[]
2025-09-09 23:17:19 +02:00
)
)),
2025-09-09 12:07:53 +02:00
$vcalendar->events
2025-09-09 23:17:19 +02:00
)
)
);
}
/**
*/
private function retrieve(
2025-09-21 18:49:03 +02:00
string $url,
?string $realm_name
2025-09-09 23:17:19 +02:00
)
{
$client = new \Sabre\HTTP\Client();
$request = new \Sabre\HTTP\Request(
'GET',
2025-09-10 15:03:44 +02:00
$url,
2025-09-09 23:17:19 +02:00
[],
null
);
$response = $client->send($request);
$status_code = $response->getStatus();
switch ($status_code)
{
case 200:
{
$ics = $response->getBody();
try
{
$vcalendar = \davina\helpers\ics\vcalendar_decode($ics);
}
catch (\Throwable $throwable)
{
\error_log(
\davina\helpers\string_\coin(
'could not parse ics: {{reason}}',
[
'reason' => \strval($throwable),
]
)
);
$valendar = null;
}
if ($vcalendar === null)
{
throw (new \Exception('could not parse ics'));
}
else
{
$calendar = $this->vcalendar_to_calendar($vcalendar, $realm_name);
$calendar_raw = \davina\model\calendar_to_raw($calendar);
return $calendar_raw;
}
2025-09-09 12:07:53 +02:00
break;
}
default:
{
2025-09-09 23:17:19 +02:00
throw (
new \Exception(
\sprintf(
'unhandled response status code: %u',
$status_code
)
)
);
2025-09-09 12:07:53 +02:00
break;
}
}
}
/**
* [implementation]
*/
2025-09-21 13:27:37 +02:00
public function read(
2025-09-16 12:05:35 +02:00
) : \davina\model\struct_calendar
2025-09-09 12:07:53 +02:00
{
2025-09-21 18:49:03 +02:00
$parameters = \davina\get_parameters();
$url = $this->url($parameters);
$key = \sprintf(
'%s:%u',
$url,
$this->conflate
);
2025-09-10 15:03:44 +02:00
$f1 = fn() => $this->retrieve(
2025-09-21 18:49:03 +02:00
$url,
$parameters['realm_name']
2025-09-10 15:03:44 +02:00
);
2025-09-16 12:05:35 +02:00
$f2 = fn() => \davina\helpers\cache\get(
2025-09-09 23:17:19 +02:00
$this->cache_file,
$key,
$f1,
[
'ttl' => $this->lifetime,
]
);
2025-09-16 12:05:35 +02:00
$f3 = fn() => \davina\helpers\cache\get(
2025-09-09 12:07:53 +02:00
$this->cache_memory,
$key,
2025-09-09 23:17:19 +02:00
$f2,
2025-09-09 12:07:53 +02:00
[
'ttl' => null,
]
);
2025-09-16 12:05:35 +02:00
return \davina\model\calendar_from_raw(
2025-09-09 23:17:19 +02:00
($f3)()
);
2025-09-09 12:07:53 +02:00
}
}
?>