150 lines
4.6 KiB
PHP
150 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
final class NotificationRepository
|
|
{
|
|
private string $systemPath;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->systemPath = storage_path('system/notifications.json');
|
|
}
|
|
|
|
public function systemConfig(): array
|
|
{
|
|
$config = decode_json_file($this->systemPath, []);
|
|
$changed = false;
|
|
|
|
if (!isset($config['cron_token']) || !is_string($config['cron_token']) || $config['cron_token'] === '') {
|
|
$config['cron_token'] = bin2hex(random_bytes(24));
|
|
$changed = true;
|
|
}
|
|
|
|
if (!isset($config['subject']) || !is_string($config['subject']) || $config['subject'] === '') {
|
|
$host = parse_url(app_origin(), PHP_URL_HOST);
|
|
$host = is_string($host) && $host !== '' ? $host : 'localhost';
|
|
$config['subject'] = 'mailto:hello@' . $host;
|
|
$changed = true;
|
|
}
|
|
|
|
if ($changed) {
|
|
$this->writeJson($this->systemPath, $config);
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
public function saveVapidKeys(string $publicKey, string $privateKey): void
|
|
{
|
|
$config = $this->systemConfig();
|
|
$config['vapid_public_key'] = $publicKey;
|
|
$config['vapid_private_key'] = $privateKey;
|
|
$this->writeJson($this->systemPath, $config);
|
|
}
|
|
|
|
public function subscriptionsForUser(string $username): array
|
|
{
|
|
$payload = decode_json_file($this->subscriptionsPath($username), ['subscriptions' => []]);
|
|
|
|
return array_values(array_filter($payload['subscriptions'] ?? [], 'is_array'));
|
|
}
|
|
|
|
public function saveSubscription(string $username, array $subscription): void
|
|
{
|
|
$endpoint = trim((string) ($subscription['endpoint'] ?? ''));
|
|
if ($endpoint === '') {
|
|
throw new RuntimeException('Die Subscription ist unvollständig.');
|
|
}
|
|
|
|
$subscriptions = $this->subscriptionsForUser($username);
|
|
$saved = false;
|
|
|
|
foreach ($subscriptions as &$entry) {
|
|
if (($entry['endpoint'] ?? '') === $endpoint) {
|
|
$entry = array_merge($entry, $subscription, [
|
|
'updated_at' => date(DATE_ATOM),
|
|
]);
|
|
$saved = true;
|
|
break;
|
|
}
|
|
}
|
|
unset($entry);
|
|
|
|
if (!$saved) {
|
|
$subscription['created_at'] = date(DATE_ATOM);
|
|
$subscription['updated_at'] = date(DATE_ATOM);
|
|
$subscriptions[] = $subscription;
|
|
}
|
|
|
|
$this->writeJson($this->subscriptionsPath($username), ['subscriptions' => array_values($subscriptions)]);
|
|
}
|
|
|
|
public function removeSubscription(string $username, string $endpoint): void
|
|
{
|
|
$endpoint = trim($endpoint);
|
|
if ($endpoint === '') {
|
|
return;
|
|
}
|
|
|
|
$subscriptions = array_values(array_filter(
|
|
$this->subscriptionsForUser($username),
|
|
static fn (array $entry): bool => ($entry['endpoint'] ?? '') !== $endpoint
|
|
));
|
|
|
|
$this->writeJson($this->subscriptionsPath($username), ['subscriptions' => $subscriptions]);
|
|
}
|
|
|
|
public function removeInvalidSubscriptions(string $username, array $endpoints): void
|
|
{
|
|
foreach ($endpoints as $endpoint) {
|
|
if (is_string($endpoint) && $endpoint !== '') {
|
|
$this->removeSubscription($username, $endpoint);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function reminderState(string $username): array
|
|
{
|
|
return decode_json_file($this->reminderStatePath($username), []);
|
|
}
|
|
|
|
public function saveReminderState(string $username, array $state): void
|
|
{
|
|
$this->writeJson($this->reminderStatePath($username), $state);
|
|
}
|
|
|
|
public function subscriptionCount(string $username): int
|
|
{
|
|
return count($this->subscriptionsForUser($username));
|
|
}
|
|
|
|
private function subscriptionsPath(string $username): string
|
|
{
|
|
return storage_path('users/' . normalize_username($username) . '/push-subscriptions.json');
|
|
}
|
|
|
|
private function reminderStatePath(string $username): string
|
|
{
|
|
return storage_path('users/' . normalize_username($username) . '/notification-state.json');
|
|
}
|
|
|
|
private function writeJson(string $path, array $payload): void
|
|
{
|
|
$directory = dirname($path);
|
|
if (!is_dir($directory)) {
|
|
mkdir($directory, 0775, true);
|
|
}
|
|
|
|
$bytes = file_put_contents(
|
|
$path,
|
|
json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
|
LOCK_EX
|
|
);
|
|
|
|
if ($bytes === false) {
|
|
throw new RuntimeException('Die Benachrichtigungsdaten konnten nicht gespeichert werden.');
|
|
}
|
|
}
|
|
}
|