Compare commits
3 commits
64c887275a
...
93abd2dfd8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93abd2dfd8 | ||
|
|
baea0378fb | ||
|
|
a8fbce49b0 |
39
source/auths/_factory.php
Normal file
39
source/auths/_factory.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace davina\auths;
|
||||
|
||||
require_once(DIR_LOGIC . '/auths/_interface.php');
|
||||
require_once(DIR_LOGIC . '/auths/pass_through.php');
|
||||
require_once(DIR_LOGIC . '/auths/static.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function make(
|
||||
string $kind,
|
||||
$data
|
||||
) : \davina\auths\interface_auth
|
||||
{
|
||||
switch ($kind)
|
||||
{
|
||||
case 'pass_through':
|
||||
{
|
||||
return (new \davina\auths\class_auth_pass_through(
|
||||
));
|
||||
break;
|
||||
}
|
||||
case 'static':
|
||||
{
|
||||
return (new \davina\auths\class_auth_static(
|
||||
$data['password']
|
||||
));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new \Exception(\sprintf('unhandled auth kind: %s', $kind)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
42
source/auths/_interface.php
Normal file
42
source/auths/_interface.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace davina\auths;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
interface interface_auth
|
||||
{
|
||||
|
||||
/**
|
||||
* @param array $credentials {
|
||||
* record<
|
||||
* username:(null|string),
|
||||
* password:string
|
||||
* >
|
||||
* }
|
||||
*/
|
||||
function check(
|
||||
array $credentials
|
||||
) : bool
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
* @param array $credentials {
|
||||
* record<
|
||||
* username:(null|string),
|
||||
* password:string
|
||||
* >
|
||||
* }
|
||||
*/
|
||||
function determine_parameters(
|
||||
array $credentials
|
||||
) : array
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
39
source/auths/pass_through.php
Normal file
39
source/auths/pass_through.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace davina\auths;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class class_auth_pass_through implements interface_auth
|
||||
{
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
function check(
|
||||
array $credentials
|
||||
) : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
function determine_parameters(
|
||||
array $credentials
|
||||
) : array
|
||||
{
|
||||
return [
|
||||
'auth_username' => $credentials['username'],
|
||||
'auth_password' => $credentials['password'],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
51
source/auths/static.php
Normal file
51
source/auths/static.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace davina\auths;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class class_auth_static implements interface_auth
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private string $password;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct(
|
||||
string $password
|
||||
)
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
function check(
|
||||
array $credentials
|
||||
) : bool
|
||||
{
|
||||
return ($credentials['password'] === $this->password);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
function determine_parameters(
|
||||
array $credentials
|
||||
) : array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
159
source/conf.php
159
source/conf.php
|
|
@ -2,58 +2,26 @@
|
|||
|
||||
namespace davina\conf;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class struct_auth
|
||||
{
|
||||
public string $kind;
|
||||
public $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class struct_source_data_ics_feed
|
||||
{
|
||||
public string $url;
|
||||
public bool $combined;
|
||||
public int $lifetime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
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;
|
||||
}
|
||||
require_once(DIR_LOGIC . '/helpers/list.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class _state
|
||||
{
|
||||
public static ?struct_root $data = null;
|
||||
public static $data = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function validate_realm_name(
|
||||
string $realm_name
|
||||
) : string
|
||||
{
|
||||
$matchs = null;
|
||||
$result = preg_match('/^[0-9a-zA-Z]+$/', $realm_name, $matches);
|
||||
return ($result === 1);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -69,37 +37,86 @@ function load(
|
|||
),
|
||||
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;
|
||||
}
|
||||
_state::$data = [
|
||||
/**
|
||||
* @todo check for name duplicates
|
||||
*/
|
||||
'realms' => \davina\helpers\list_\map(
|
||||
$data_raw['realms'],
|
||||
function ($realm_raw) {
|
||||
if (! validate_realm_name($realm_raw['name']))
|
||||
{
|
||||
throw (new \Exception(\sprintf('invalid realm name: "%s"', $realm_raw['name'])));
|
||||
}
|
||||
else
|
||||
{
|
||||
return [
|
||||
'name' => $realm_raw['name'],
|
||||
'auth' => (function ($auth_raw) use ($realm_raw) {
|
||||
switch ($auth_raw['kind'])
|
||||
{
|
||||
case 'pass_through':
|
||||
{
|
||||
return [
|
||||
'kind' => 'pass_through',
|
||||
'data' => null
|
||||
];
|
||||
break;
|
||||
}
|
||||
case 'static':
|
||||
{
|
||||
return [
|
||||
'kind' => 'static',
|
||||
'data' => [
|
||||
'username' => ($auth_raw['data']['username'] ?? $realm_raw['name']),
|
||||
'password' => ($auth_raw['data']['password'] ?? $realm_raw['name']),
|
||||
]
|
||||
];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new \Exception(\sprintf('invalid auth kind: %s', $auth_raw['kind'])));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}) ($realm_raw['auth']),
|
||||
'source' => (function ($source_raw) {
|
||||
switch ($source_raw['kind'])
|
||||
{
|
||||
case 'ics_feed':
|
||||
{
|
||||
return [
|
||||
'kind' => 'ics_feed',
|
||||
'data' => [
|
||||
'url' => $source_raw['data']['url'],
|
||||
'lifetime' => ($source_raw['data']['lifetime'] ?? (60 * 15)),
|
||||
'conflate' => ($source_raw['data']['conflate'] ?? true),
|
||||
]
|
||||
];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new \Exception(\sprintf('invalid source kind: %s', $source_raw['kind'])));
|
||||
}
|
||||
}
|
||||
}) ($realm_raw['source']),
|
||||
];
|
||||
}
|
||||
}
|
||||
),
|
||||
'settings' => [
|
||||
'timezone' => (($data_raw['settings'] ?? [])['timezone'] ?? 'UTC'),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function get(
|
||||
) : struct_root
|
||||
)
|
||||
{
|
||||
if (_state::$data === null)
|
||||
{
|
||||
|
|
|
|||
35
source/helpers/list.php
Normal file
35
source/helpers/list.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace davina\helpers\list_;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function map(
|
||||
array $list,
|
||||
\Closure $function
|
||||
) : array
|
||||
{
|
||||
return \array_map(
|
||||
$function,
|
||||
$list
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function filter(
|
||||
array $list,
|
||||
\Closure $predicate
|
||||
) : array
|
||||
{
|
||||
return \array_values(
|
||||
\array_filter(
|
||||
$list,
|
||||
$predicate
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -13,7 +13,18 @@ function coin(
|
|||
$result = $template;
|
||||
foreach ($arguments as $key => $value)
|
||||
{
|
||||
$result = \str_replace(\sprintf('{{%s}}', $key), $value, $result);
|
||||
if ($value === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = \str_replace(
|
||||
\sprintf('{{%s}}', $key),
|
||||
$value,
|
||||
$result
|
||||
);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ define("DIR_LOGIC", "logic");
|
|||
require_once('vendor/autoload.php');
|
||||
require_once(DIR_LOGIC . '/base.php');
|
||||
require_once(DIR_LOGIC . '/overwrites/principal_backend.php');
|
||||
require_once(DIR_LOGIC . '/overwrites/auths/_factory.php');
|
||||
require_once(DIR_LOGIC . '/overwrites/auth_backend.php');
|
||||
require_once(DIR_LOGIC . '/overwrites/caldav_backend.php');
|
||||
require_once(DIR_LOGIC . '/sources/_factory.php');
|
||||
require_once(DIR_LOGIC . '/auths/_factory.php');
|
||||
require_once(DIR_LOGIC . '/model.php');
|
||||
require_once(DIR_LOGIC . '/conf.php');
|
||||
|
||||
|
||||
|
|
@ -20,21 +22,38 @@ function main(
|
|||
|
||||
\davina\set_parameters([]);
|
||||
|
||||
\date_default_timezone_set(\davina\conf\get()->settings->timezone);
|
||||
\date_default_timezone_set(\davina\conf\get()['settings']['timezone']);
|
||||
|
||||
$source = \davina\sources\make(
|
||||
[
|
||||
'kind' => \davina\conf\get()->source->kind,
|
||||
'data' => \davina\conf\get()->source->data,
|
||||
]
|
||||
);
|
||||
/**
|
||||
* @todo nicht einfach die realm names als keys verwenden …
|
||||
*/
|
||||
$realms = [];
|
||||
foreach (\davina\conf\get()['realms'] as $realm_raw)
|
||||
{
|
||||
$realms[$realm_raw['name']] = new \davina\model\struct_realm(
|
||||
$realm_raw['name'],
|
||||
\davina\auths\make(
|
||||
$realm_raw['auth']['kind'],
|
||||
$realm_raw['auth']['data']
|
||||
),
|
||||
\davina\sources\make(
|
||||
$realm_raw['source']['kind'],
|
||||
$realm_raw['source']['data']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$principal_backend = new \davina\overwrites\class_principle_backend();
|
||||
$principal_backend = new \davina\overwrites\class_principle_backend($realms);
|
||||
|
||||
$server = new \Sabre\DAV\Server(
|
||||
[
|
||||
new \Sabre\CalDAV\Principal\Collection($principal_backend),
|
||||
new \Sabre\CalDAV\CalendarRoot($principal_backend, new \davina\overwrites\class_caldav_backend($source)),
|
||||
new \Sabre\CalDAV\Principal\Collection(
|
||||
$principal_backend
|
||||
),
|
||||
new \Sabre\CalDAV\CalendarRoot(
|
||||
$principal_backend,
|
||||
new \davina\overwrites\class_caldav_backend($realms)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
|
|
@ -42,12 +61,8 @@ function main(
|
|||
|
||||
$server->addPlugin(
|
||||
new \Sabre\DAV\Auth\Plugin(
|
||||
\davina\overwrites\make_auth_backend(
|
||||
$source,
|
||||
[
|
||||
'kind' => \davina\conf\get()->auth->kind,
|
||||
'data' => \davina\conf\get()->auth->data,
|
||||
]
|
||||
new \davina\overwrites\class_auth_backend(
|
||||
$realms
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
@ -64,7 +79,7 @@ function main(
|
|||
/**
|
||||
* not required
|
||||
*/
|
||||
$server->addPlugin(new \Sabre\DAV\Browser\Plugin());
|
||||
// $server->addPlugin(new \Sabre\DAV\Browser\Plugin());
|
||||
|
||||
$server->start();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,4 +116,40 @@ function calendar_from_raw(
|
|||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class struct_realm
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public string $name;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public \davina\auths\interface_auth $auth;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public \davina\sources\interface_source $source;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
\davina\auths\interface_auth $auth,
|
||||
\davina\sources\interface_source $source
|
||||
)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->auth = $auth;
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
|||
86
source/overwrites/auth_backend.php
Normal file
86
source/overwrites/auth_backend.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace davina\overwrites;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
require_once(DIR_LOGIC . '/base.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class class_auth_backend
|
||||
extends \Sabre\DAV\Auth\Backend\AbstractBasic
|
||||
implements \Sabre\DAV\Auth\Backend\BackendInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array {list<\davina\sources\interface_source>}
|
||||
*/
|
||||
private array $realms;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct(
|
||||
array $realms
|
||||
)
|
||||
{
|
||||
// parent::__construct();
|
||||
$this->realms = $realms;
|
||||
$this->setRealm('davina');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
protected function validateUserPass(
|
||||
/*string */$identifier,
|
||||
/*string */$password
|
||||
)/* : bool*/
|
||||
{
|
||||
$parts = \explode('-', $identifier, 2);
|
||||
$realm_name = $parts[0];
|
||||
$credentials = [
|
||||
'username' => (
|
||||
(\count($parts) >= 2)
|
||||
?
|
||||
$parts[1]
|
||||
:
|
||||
null
|
||||
),
|
||||
'password' => $password,
|
||||
];
|
||||
|
||||
if (! \array_key_exists($realm_name, $this->realms))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$realm = $this->realms[$realm_name];
|
||||
if (! $realm->auth->check($credentials))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* @todo check for security
|
||||
*/
|
||||
\davina\set_parameters(
|
||||
\array_merge(
|
||||
$realm->auth->determine_parameters($credentials),
|
||||
[
|
||||
'realm_name' => $realm_name,
|
||||
]
|
||||
)
|
||||
);
|
||||
$data = $realm->source->read();
|
||||
return ($data !== null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace davina\overwrites;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
require_once(DIR_LOGIC . '/sources/_interface.php');
|
||||
require_once(DIR_LOGIC . '/overwrites/auths/none.php');
|
||||
require_once(DIR_LOGIC . '/overwrites/auths/basic.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function make_auth_backend(
|
||||
\davina\sources\interface_source $source,
|
||||
array $descriptor
|
||||
) : \Sabre\DAV\Auth\Backend\BackendInterface
|
||||
{
|
||||
switch ($descriptor['kind'])
|
||||
{
|
||||
case 'none':
|
||||
{
|
||||
return (new \davina\overwrites\class_auth_backend_none());
|
||||
break;
|
||||
}
|
||||
case 'basic':
|
||||
{
|
||||
return (new \davina\overwrites\class_auth_backend_basic($source));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new \Exception(\sprintf('unhandled auth backend kind: %s', $descriptor['kind'])));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace davina\overwrites;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
require_once(DIR_LOGIC . '/base.php');
|
||||
require_once(DIR_LOGIC . '/sources/_interface.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class class_auth_backend_basic
|
||||
extends \Sabre\DAV\Auth\Backend\AbstractBasic
|
||||
implements \Sabre\DAV\Auth\Backend\BackendInterface
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private \davina\sources\interface_source $source;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct(
|
||||
\davina\sources\interface_source $source
|
||||
)
|
||||
{
|
||||
// parent::__construct();
|
||||
$this->source = $source;
|
||||
$this->setRealm('davina');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
protected function validateUserPass(
|
||||
/*string */$username,
|
||||
/*string */$password
|
||||
)/* : bool*/
|
||||
{
|
||||
$parameters = [
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
];
|
||||
/**
|
||||
* @todo check for security
|
||||
*/
|
||||
\davina\set_parameters($parameters);
|
||||
$data = $this->source->get(/*$parameters*/[]);
|
||||
return ($data !== null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace davina\overwrites;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
require_once(DIR_LOGIC . '/sources/_interface.php');
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
class class_auth_backend_none
|
||||
implements \Sabre\DAV\Auth\Backend\BackendInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @todo other principal uri?
|
||||
*/
|
||||
public function check(
|
||||
\Sabre\HTTP\RequestInterface $request,
|
||||
\Sabre\HTTP\ResponseInterface $response
|
||||
)
|
||||
{
|
||||
return [true, 'principals/dummy'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function challenge(
|
||||
\Sabre\HTTP\RequestInterface $request,
|
||||
\Sabre\HTTP\ResponseInterface $response
|
||||
)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -4,9 +4,9 @@ namespace davina\overwrites;
|
|||
|
||||
require_once('vendor/autoload.php');
|
||||
require_once(DIR_LOGIC . '/helpers/call.php');
|
||||
require_once(DIR_LOGIC . '/helpers/list.php');
|
||||
require_once(DIR_LOGIC . '/helpers/ics.php');
|
||||
require_once(DIR_LOGIC . '/model.php');
|
||||
require_once(DIR_LOGIC . '/sources/_interface.php');
|
||||
require_once(DIR_LOGIC . '/conf.php');
|
||||
|
||||
|
||||
|
|
@ -19,50 +19,25 @@ class class_caldav_backend
|
|||
|
||||
|
||||
/**
|
||||
* @var array {map<string, \davina\model\struct_realm>}
|
||||
*/
|
||||
private \davina\sources\interface_source $source;
|
||||
private array $realms;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private ?string $selected_realm_name;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct(
|
||||
\davina\sources\interface_source $source
|
||||
array $realms
|
||||
)
|
||||
{
|
||||
// parent::__construct();
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private function hash_tag(
|
||||
string $tag
|
||||
) : string
|
||||
{
|
||||
return \hash('sha256', $tag);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
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),
|
||||
]
|
||||
);
|
||||
$this->realms = $realms;
|
||||
$this->selected_realm_name = null;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -125,6 +100,118 @@ class class_caldav_backend
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private function encode_tag(
|
||||
?string $tag
|
||||
) : ?string
|
||||
{
|
||||
if ($tag === null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
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<
|
||||
* realm_name:string,
|
||||
* calendar_name:(null|string),
|
||||
* >
|
||||
* }
|
||||
*/
|
||||
private function encode_calendar_identifier(
|
||||
array $parameters
|
||||
) : string
|
||||
{
|
||||
$str = $parameters['realm_name'];
|
||||
if ($parameters['calendar_name'] === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
$str .= \sprintf(
|
||||
'-%s',
|
||||
$parameters['calendar_name']
|
||||
);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array {
|
||||
* record<
|
||||
* realm_name:string,
|
||||
* calendar_name:(null|string),
|
||||
* >
|
||||
* }
|
||||
*/
|
||||
private function decode_calendar_identifier(
|
||||
string $str
|
||||
) : array
|
||||
{
|
||||
$parts = \explode('-', $str, 2);
|
||||
return [
|
||||
'realm_name' => $parts[0],
|
||||
'calendar_name' => (
|
||||
(count($parts) < 2)
|
||||
?
|
||||
null
|
||||
:
|
||||
$parts[1]
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private function get_source(
|
||||
string $realm_name
|
||||
) : \davina\sources\interface_source
|
||||
{
|
||||
if (
|
||||
($this->selected_realm_name === null)
|
||||
||
|
||||
($this->selected_realm_name === $realm_name)
|
||||
)
|
||||
{
|
||||
$this->selected_realm_name = $realm_name;
|
||||
if (! \array_key_exists($realm_name, $this->realms))
|
||||
{
|
||||
throw (new \Exception(\sprintf('no such realm: %s', $realm_name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->realms[$realm_name]->source;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new \Exception('may not change source'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
|
|
@ -132,7 +219,11 @@ class class_caldav_backend
|
|||
$principalUri
|
||||
)
|
||||
{
|
||||
$calendar = $this->source->get([]);
|
||||
// $source = $this->source;
|
||||
// $realm_name = \explode('/', $principalUri)[1];
|
||||
$realm_name = \davina\get_parameters()['realm_name'];
|
||||
$source = $this->get_source($realm_name);
|
||||
$calendar = $source->read();
|
||||
$tags = [];
|
||||
foreach ($calendar->events as $event)
|
||||
{
|
||||
|
|
@ -141,18 +232,42 @@ class class_caldav_backend
|
|||
$tags[$tag] = null;
|
||||
}
|
||||
}
|
||||
$result = \array_map(
|
||||
fn($tag) => [
|
||||
'id' => $this->hash_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']),
|
||||
return \davina\helpers\call\convey(
|
||||
$tags,
|
||||
[
|
||||
fn($x) => (
|
||||
(\count($x) <= 0)
|
||||
?
|
||||
[null]
|
||||
:
|
||||
\array_keys($x)
|
||||
),
|
||||
fn($x) => \davina\helpers\list_\map(
|
||||
$x,
|
||||
fn($tag) => [
|
||||
'id' => $this->encode_calendar_identifier(
|
||||
[
|
||||
'realm_name' => $realm_name,
|
||||
'calendar_name' => $this->encode_tag($tag),
|
||||
]
|
||||
),
|
||||
// 'uri' => $this->encode_tag($tag),
|
||||
'uri' => $this->encode_calendar_identifier(
|
||||
[
|
||||
'realm_name' => $realm_name,
|
||||
'calendar_name' => $this->encode_tag($tag),
|
||||
]
|
||||
),
|
||||
'principaluri' => $principalUri,
|
||||
'{DAV:}displayname' => ($tag ?? $realm_name),
|
||||
\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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -187,34 +302,46 @@ class class_caldav_backend
|
|||
$calendarId
|
||||
)
|
||||
{
|
||||
$tag = $calendarId;
|
||||
$calendar = $this->source->get([]);
|
||||
$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->hash_tag($x),
|
||||
$event->tags
|
||||
$calendar_identifier = $this->decode_calendar_identifier($calendarId);
|
||||
// $realm_name = $calendar_identifier['realm_name'];
|
||||
$realm_name = \davina\get_parameters()['realm_name'];
|
||||
$source = $this->get_source($realm_name);
|
||||
$tag = $calendar_identifier['calendar_name'];
|
||||
$calendar = $source->read();
|
||||
|
||||
return \davina\helpers\call\convey(
|
||||
$calendar->events,
|
||||
[
|
||||
fn($x) => \davina\helpers\list_\filter(
|
||||
$x,
|
||||
fn($event) => (
|
||||
(\count($event->tags) <= 0)
|
||||
||
|
||||
\in_array(
|
||||
$tag,
|
||||
\davina\helpers\list_\map(
|
||||
$event->tags,
|
||||
fn($x) => $this->encode_tag($x)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
fn($x) => \davina\helpers\list_\map(
|
||||
$x,
|
||||
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,
|
||||
],
|
||||
),
|
||||
]
|
||||
);
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -227,12 +354,16 @@ class class_caldav_backend
|
|||
)
|
||||
{
|
||||
$id = $objectUri;
|
||||
$calendar = $this->source->get([]);
|
||||
$events = \array_values(
|
||||
\array_filter(
|
||||
$calendar->events,
|
||||
fn($event) => ($event->id === $id)
|
||||
)
|
||||
$calendar_identifier = $this->decode_calendar_identifier($calendarId);
|
||||
// $realm_name = $calendar_identifier['realm_name'];
|
||||
$realm_name = \davina\get_parameters()['realm_name'];
|
||||
$source = $this->get_source($realm_name);
|
||||
$tag = $calendar_identifier['calendar_name'];
|
||||
$calendar = $source->read();
|
||||
|
||||
$events = \davina\helpers\list_\filter(
|
||||
$calendar->events,
|
||||
fn($event) => ($event->id === $id)
|
||||
);
|
||||
if (\count($events) < 1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace davina\overwrites;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
require_once(DIR_LOGIC . '/helpers/list.php');
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -12,17 +13,33 @@ class class_principle_backend
|
|||
{
|
||||
|
||||
/**
|
||||
* @var array {map<string, \davina\model\struct_realm>}
|
||||
*/
|
||||
public function getPrincipalsByPrefix($prefixPath)
|
||||
private array $realms;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function __construct(
|
||||
array $realms
|
||||
)
|
||||
{
|
||||
$this->realms = $realms;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function getPrincipalsByPrefix(
|
||||
$prefixPath
|
||||
)
|
||||
{
|
||||
throw (new \Exception('not implemented: getPrincipalsByPrefix'));
|
||||
/*
|
||||
return [
|
||||
[
|
||||
'uri' => 'principals/dummy',
|
||||
]
|
||||
'uri' => 'principals/-',
|
||||
'{DAV:}displayname' => 'default',
|
||||
],
|
||||
];
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -32,7 +49,6 @@ class class_principle_backend
|
|||
$path
|
||||
)
|
||||
{
|
||||
// throw (new \Exception('not implemented: getPrincipalByPath'));
|
||||
$parts = \explode('/', $path);
|
||||
$username = $parts[1];
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -2,30 +2,26 @@
|
|||
|
||||
namespace davina\sources;
|
||||
|
||||
require_once(DIR_LOGIC . '/sources/_interface.php');
|
||||
require_once(DIR_LOGIC . '/sources/ics_feed.php');
|
||||
|
||||
|
||||
/**
|
||||
* @param array $descriptor {
|
||||
* record<
|
||||
* kind:string,
|
||||
* data:any
|
||||
* >
|
||||
* }
|
||||
*/
|
||||
function make(
|
||||
array $descriptor
|
||||
string $kind,
|
||||
$data
|
||||
) : interface_source
|
||||
{
|
||||
switch ($descriptor['kind'])
|
||||
switch ($kind)
|
||||
{
|
||||
case 'ics_feed':
|
||||
{
|
||||
return (
|
||||
new class_source_ics_feed(
|
||||
$descriptor['data']['url'],
|
||||
($descriptor['data']['lifetime'] ?? (60 * 15)),
|
||||
($descriptor['data']['combine'] ?? false)
|
||||
$data['url'],
|
||||
$data['lifetime'],
|
||||
$data['conflate']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
@ -35,7 +31,7 @@ function make(
|
|||
new \Exception(
|
||||
\sprintf(
|
||||
'unhandled source kind: %s',
|
||||
$descriptor['kind']
|
||||
$kind
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
@ -44,4 +40,4 @@ function make(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -9,15 +9,8 @@ interface interface_source
|
|||
{
|
||||
|
||||
/**
|
||||
* @param array $parameters {
|
||||
* record<
|
||||
* username:(null|string),
|
||||
* password:(null|string),
|
||||
* >
|
||||
* }
|
||||
*/
|
||||
public function get(
|
||||
array $parameters
|
||||
public function read(
|
||||
) : \davina\model\struct_calendar
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ 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');
|
||||
require_once(DIR_LOGIC . '/sources/_interface.php');
|
||||
require_once(DIR_LOGIC . '/model.php');
|
||||
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ class class_source_ics_feed
|
|||
|
||||
/**
|
||||
*/
|
||||
private bool $combine;
|
||||
private bool $conflate;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -36,12 +37,12 @@ class class_source_ics_feed
|
|||
public function __construct(
|
||||
string $url_template,
|
||||
?int $lifetime,
|
||||
bool $combine
|
||||
bool $conflate
|
||||
)
|
||||
{
|
||||
$this->url_template = $url_template;
|
||||
$this->lifetime = $lifetime;
|
||||
$this->combine = $combine;
|
||||
$this->conflate = $conflate;
|
||||
$this->cache_file = \davina\helpers\call\convey(
|
||||
new \davina\helpers\cache\class_cache_file('data'),
|
||||
[
|
||||
|
|
@ -68,7 +69,10 @@ class class_source_ics_feed
|
|||
{
|
||||
return \davina\helpers\string_\coin(
|
||||
$this->url_template,
|
||||
$parameters
|
||||
[
|
||||
'username' => ($parameters['auth_username'] ?? null),
|
||||
'password' => ($parameters['auth_password'] ?? null),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +80,8 @@ class class_source_ics_feed
|
|||
/**
|
||||
*/
|
||||
private function vcalendar_to_calendar(
|
||||
\davina\helpers\ics\struct_vcalendar $vcalendar
|
||||
\davina\helpers\ics\struct_vcalendar $vcalendar,
|
||||
?string $realm_name
|
||||
) : \davina\model\struct_calendar
|
||||
{
|
||||
return (
|
||||
|
|
@ -87,8 +92,10 @@ class class_source_ics_feed
|
|||
$vevent->uid,
|
||||
// title
|
||||
(
|
||||
$this->combine
|
||||
(! $this->conflate)
|
||||
?
|
||||
$vevent->summary
|
||||
:
|
||||
\sprintf(
|
||||
'%s%s',
|
||||
$vevent->summary,
|
||||
|
|
@ -100,8 +107,6 @@ class class_source_ics_feed
|
|||
)
|
||||
)
|
||||
)
|
||||
:
|
||||
$vevent->summary
|
||||
),
|
||||
// begin
|
||||
\davina\helpers\ics\datetime_to_unix_timestamp($vevent->dtstart->value),
|
||||
|
|
@ -119,11 +124,11 @@ class class_source_ics_feed
|
|||
$vevent->description,
|
||||
// 'tags
|
||||
(
|
||||
$this->combine
|
||||
(! $this->conflate)
|
||||
?
|
||||
['combined']
|
||||
:
|
||||
$vevent->categories
|
||||
:
|
||||
[]
|
||||
)
|
||||
)),
|
||||
$vcalendar->events
|
||||
|
|
@ -136,7 +141,8 @@ class class_source_ics_feed
|
|||
/**
|
||||
*/
|
||||
private function retrieve(
|
||||
string $url
|
||||
string $url,
|
||||
?string $realm_name
|
||||
)
|
||||
{
|
||||
$client = new \Sabre\HTTP\Client();
|
||||
|
|
@ -154,7 +160,7 @@ class class_source_ics_feed
|
|||
{
|
||||
$ics = $response->getBody();
|
||||
$vcalendar = \davina\helpers\ics\vcalendar_decode($ics);
|
||||
$calendar = $this->vcalendar_to_calendar($vcalendar);
|
||||
$calendar = $this->vcalendar_to_calendar($vcalendar, $realm_name);
|
||||
$calendar_raw = \davina\model\calendar_to_raw($calendar);
|
||||
return $calendar_raw;
|
||||
break;
|
||||
|
|
@ -178,14 +184,19 @@ class class_source_ics_feed
|
|||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public function get(
|
||||
array $parameters
|
||||
public function read(
|
||||
) : \davina\model\struct_calendar
|
||||
{
|
||||
$url = $this->url(\davina\get_parameters());
|
||||
$key = $url;
|
||||
$parameters = \davina\get_parameters();
|
||||
$url = $this->url($parameters);
|
||||
$key = \sprintf(
|
||||
'%s:%u',
|
||||
$url,
|
||||
$this->conflate
|
||||
);
|
||||
$f1 = fn() => $this->retrieve(
|
||||
$url
|
||||
$url,
|
||||
$parameters['realm_name']
|
||||
);
|
||||
$f2 = fn() => \davina\helpers\cache\get(
|
||||
$this->cache_file,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ def main():
|
|||
"--links",
|
||||
"--verbose",
|
||||
"--exclude='conf.json'",
|
||||
"--exclude='data'",
|
||||
("%s/" % args.build_directory),
|
||||
(
|
||||
("%s" % args.target_directory)
|
||||
|
|
|
|||
Loading…
Reference in a new issue