Add PWA reminders and flexible walk scoring
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
<?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.');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user