Add optional pain tracking and fix reminder delivery
This commit is contained in:
+110
-51
@@ -31,6 +31,7 @@ final class App
|
||||
|
||||
$path = request_path();
|
||||
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
|
||||
$this->triggerReminderCheckFromTraffic($method, $path);
|
||||
$hasUsers = $this->users->hasAnyUsers();
|
||||
$isAuthenticated = $this->auth->check();
|
||||
$systemPaths = ['/reminders/run'];
|
||||
@@ -252,6 +253,8 @@ final class App
|
||||
'mood' => 6,
|
||||
'energy' => 6,
|
||||
'stress' => 4,
|
||||
'pain' => 1,
|
||||
'pain_enabled' => !empty($settings['tracking']['pain_enabled']),
|
||||
'sleep_hours' => 7,
|
||||
'sleep_feeling' => 3,
|
||||
'sport_minutes' => 0,
|
||||
@@ -260,9 +263,11 @@ final class App
|
||||
'walk_mode' => (string) ($settings['walk']['mode'] ?? 'time'),
|
||||
'walk_minutes' => 0,
|
||||
'walk_steps' => 0,
|
||||
'alcohol' => false,
|
||||
'note' => '',
|
||||
];
|
||||
|
||||
$entry['pain_enabled'] = !empty($settings['tracking']['pain_enabled']);
|
||||
$entry = $this->scoring->normalize($entry);
|
||||
$previousEntry = $this->entries->find($user['username'], shift_date($date, -1));
|
||||
$evaluation = $this->scoring->evaluate($entry, $settings, $previousEntry);
|
||||
@@ -297,6 +302,8 @@ final class App
|
||||
'mood' => $_POST['mood'] ?? 5,
|
||||
'energy' => $_POST['energy'] ?? 5,
|
||||
'stress' => $_POST['stress'] ?? 5,
|
||||
'pain' => $_POST['pain'] ?? 1,
|
||||
'pain_enabled' => !empty($settings['tracking']['pain_enabled']),
|
||||
'sleep_hours' => $_POST['sleep_hours'] ?? 0,
|
||||
'sleep_feeling' => $_POST['sleep_feeling'] ?? 3,
|
||||
'sport_minutes' => $_POST['sport_minutes'] ?? 0,
|
||||
@@ -304,6 +311,7 @@ final class App
|
||||
'walk_mode' => $_POST['walk_mode'] ?? ($settings['walk']['mode'] ?? 'time'),
|
||||
'walk_minutes' => $_POST['walk_minutes'] ?? 0,
|
||||
'walk_steps' => $_POST['walk_steps'] ?? 0,
|
||||
'alcohol' => $_POST['alcohol'] ?? false,
|
||||
'note' => $_POST['note'] ?? '',
|
||||
]);
|
||||
|
||||
@@ -344,6 +352,7 @@ final class App
|
||||
'authUser' => $user,
|
||||
'entries' => $archive,
|
||||
'selectedEntry' => $selectedEntry,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -390,6 +399,8 @@ final class App
|
||||
'mood' => 10,
|
||||
'energy' => 10,
|
||||
'stress' => 1,
|
||||
'pain' => 1,
|
||||
'pain_enabled' => !empty($settings['tracking']['pain_enabled']),
|
||||
'sleep_hours' => 7,
|
||||
'sleep_feeling' => 5,
|
||||
'sport_minutes' => 999,
|
||||
@@ -400,6 +411,7 @@ final class App
|
||||
'walk_mode' => (string) ($settings['walk']['mode'] ?? 'time'),
|
||||
'walk_minutes' => 999,
|
||||
'walk_steps' => 10000,
|
||||
'alcohol' => false,
|
||||
'note' => 'x',
|
||||
], $settings)['max_total'],
|
||||
]);
|
||||
@@ -598,8 +610,12 @@ final class App
|
||||
$settings['scoring']['mood_multiplier'] = max(0, min(10, (int) ($input['scoring']['mood_multiplier'] ?? 3)));
|
||||
$settings['scoring']['energy_multiplier'] = max(0, min(10, (int) ($input['scoring']['energy_multiplier'] ?? 2)));
|
||||
$settings['scoring']['stress_multiplier'] = max(0, min(10, (int) ($input['scoring']['stress_multiplier'] ?? 2)));
|
||||
$settings['scoring']['pain_multiplier'] = max(0, min(10, (int) ($input['scoring']['pain_multiplier'] ?? ($settings['scoring']['pain_multiplier'] ?? 3))));
|
||||
$settings['scoring']['sleep_feeling_multiplier'] = max(0, min(10, (int) ($input['scoring']['sleep_feeling_multiplier'] ?? 2)));
|
||||
$settings['scoring']['journal_points'] = max(0, min(20, (int) ($input['scoring']['journal_points'] ?? 2)));
|
||||
$settings['tracking'] = [
|
||||
'pain_enabled' => isset($input['tracking']['pain_enabled']) && $input['tracking']['pain_enabled'] === '1',
|
||||
];
|
||||
|
||||
foreach ($defaults['scoring']['sleep_duration_points'] as $key => $default) {
|
||||
$settings['scoring']['sleep_duration_points'][$key] = max(0, min(20, (int) ($input['scoring']['sleep_duration_points'][$key] ?? $default)));
|
||||
@@ -663,6 +679,10 @@ final class App
|
||||
Defaults::settings()['walk'],
|
||||
is_array($settings['walk'] ?? null) ? $settings['walk'] : []
|
||||
);
|
||||
$settings['tracking'] = array_replace(
|
||||
Defaults::settings()['tracking'],
|
||||
is_array($settings['tracking'] ?? null) ? $settings['tracking'] : []
|
||||
);
|
||||
$settings['notifications'] = array_replace(
|
||||
Defaults::settings()['notifications'],
|
||||
is_array($settings['notifications'] ?? null) ? $settings['notifications'] : []
|
||||
@@ -855,60 +875,15 @@ final class App
|
||||
json_response(['ok' => false, 'message' => 'Ungültiger Reminder-Token.'], 403);
|
||||
}
|
||||
|
||||
$now = new DateTimeImmutable('now');
|
||||
$today = $now->format('Y-m-d');
|
||||
$currentTime = $now->format('H:i');
|
||||
$processed = 0;
|
||||
$sentUsers = 0;
|
||||
$alreadyTracked = 0;
|
||||
$skipped = 0;
|
||||
$removed = 0;
|
||||
|
||||
foreach ($this->users->all() as $account) {
|
||||
$username = (string) ($account['username'] ?? '');
|
||||
if ($username === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$processed++;
|
||||
$settings = $this->hydrateSettings($this->settings->forUser($username));
|
||||
$state = $this->notifications->reminderState($username);
|
||||
|
||||
if (!$this->isReminderDue($settings, $state, $today, $currentTime)) {
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->entries->find($username, $today) !== null) {
|
||||
$alreadyTracked++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = $this->sendNotificationsForUser($username, [
|
||||
'title' => 'Mood-Board',
|
||||
'body' => 'Nimm dir kurz Zeit für deinen heutigen Eintrag.',
|
||||
'url' => '/track?date=' . rawurlencode($today),
|
||||
'tag' => 'mood-reminder-' . $today,
|
||||
]);
|
||||
|
||||
$removed += $result['removed'];
|
||||
|
||||
if ($result['sent'] > 0) {
|
||||
$sentUsers++;
|
||||
$this->notifications->saveReminderState($username, [
|
||||
'last_sent_date' => $today,
|
||||
'last_sent_at' => date(DATE_ATOM),
|
||||
]);
|
||||
}
|
||||
}
|
||||
$stats = $this->runDueReminders(new DateTimeImmutable('now'));
|
||||
|
||||
json_response([
|
||||
'ok' => true,
|
||||
'processed' => $processed,
|
||||
'sent_users' => $sentUsers,
|
||||
'already_tracked' => $alreadyTracked,
|
||||
'skipped' => $skipped,
|
||||
'removed_subscriptions' => $removed,
|
||||
'processed' => $stats['processed'],
|
||||
'sent_users' => $stats['sent_users'],
|
||||
'already_tracked' => $stats['already_tracked'],
|
||||
'skipped' => $stats['skipped'],
|
||||
'removed_subscriptions' => $stats['removed_subscriptions'],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -968,4 +943,88 @@ final class App
|
||||
|
||||
return (string) ($state['last_sent_date'] ?? '') !== $today;
|
||||
}
|
||||
|
||||
private function triggerReminderCheckFromTraffic(string $method, string $path): void
|
||||
{
|
||||
if ($method !== 'GET' || $path === '/reminders/run') {
|
||||
return;
|
||||
}
|
||||
|
||||
$lockPath = storage_path('system/reminder-traffic.lock');
|
||||
$handle = fopen($lockPath, 'c+');
|
||||
if ($handle === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!flock($handle, LOCK_EX | LOCK_NB)) {
|
||||
fclose($handle);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->runDueReminders(new DateTimeImmutable('now'));
|
||||
} catch (Throwable) {
|
||||
// Reminder checks should never break normal page delivery.
|
||||
}
|
||||
|
||||
flock($handle, LOCK_UN);
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
private function runDueReminders(DateTimeImmutable $now): array
|
||||
{
|
||||
$today = $now->format('Y-m-d');
|
||||
$currentTime = $now->format('H:i');
|
||||
$processed = 0;
|
||||
$sentUsers = 0;
|
||||
$alreadyTracked = 0;
|
||||
$skipped = 0;
|
||||
$removed = 0;
|
||||
|
||||
foreach ($this->users->all() as $account) {
|
||||
$username = (string) ($account['username'] ?? '');
|
||||
if ($username === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$processed++;
|
||||
$settings = $this->hydrateSettings($this->settings->forUser($username));
|
||||
$state = $this->notifications->reminderState($username);
|
||||
|
||||
if (!$this->isReminderDue($settings, $state, $today, $currentTime)) {
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->entries->find($username, $today) !== null) {
|
||||
$alreadyTracked++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = $this->sendNotificationsForUser($username, [
|
||||
'title' => 'Mood-Board',
|
||||
'body' => 'Nimm dir kurz Zeit für deinen heutigen Eintrag.',
|
||||
'url' => '/track?date=' . rawurlencode($today),
|
||||
'tag' => 'mood-reminder-' . $today,
|
||||
]);
|
||||
|
||||
$removed += $result['removed'];
|
||||
|
||||
if ($result['sent'] > 0) {
|
||||
$sentUsers++;
|
||||
$this->notifications->saveReminderState($username, [
|
||||
'last_sent_date' => $today,
|
||||
'last_sent_at' => $now->format(DATE_ATOM),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'processed' => $processed,
|
||||
'sent_users' => $sentUsers,
|
||||
'already_tracked' => $alreadyTracked,
|
||||
'skipped' => $skipped,
|
||||
'removed_subscriptions' => $removed,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user