add health import

This commit is contained in:
2026-05-19 14:50:19 +02:00
parent bc6e850afb
commit e36f27da4a
12 changed files with 1843 additions and 14 deletions
+252 -1
View File
@@ -38,7 +38,7 @@ final class UserRepository
public function verify(string $username, string $password): ?array
{
$user = $this->find($username);
$user = $this->find($username) ?? [];
if ($user === null) {
return null;
@@ -51,6 +51,257 @@ final class UserRepository
return $user;
}
public function findByRememberToken(string $selector, string $validator): ?array
{
$validatorHash = hash('sha256', $validator);
$now = time();
foreach ($this->all() as $user) {
$token = $user['remember_token'] ?? null;
if (!is_array($token) || !hash_equals((string) ($token['selector'] ?? ''), $selector)) {
continue;
}
$expiresAt = strtotime((string) ($token['expires_at'] ?? '')) ?: 0;
if ($expiresAt < $now) {
return null;
}
if (!hash_equals((string) ($token['validator_hash'] ?? ''), $validatorHash)) {
return null;
}
return $user;
}
return null;
}
public function storeRememberToken(string $username, string $selector, string $validatorHash, int $expiresAt): void
{
$normalized = normalize_username($username);
$users = $this->all();
$updated = false;
foreach ($users as &$user) {
if (($user['username'] ?? '') !== $normalized) {
continue;
}
$user['remember_token'] = [
'selector' => $selector,
'validator_hash' => $validatorHash,
'expires_at' => date(DATE_ATOM, $expiresAt),
'created_at' => date(DATE_ATOM),
];
$user['updated_at'] = date(DATE_ATOM);
$updated = true;
break;
}
unset($user);
if (!$updated) {
throw new RuntimeException('Der Remember-Me-Token konnte keinem Benutzer zugeordnet werden.');
}
$this->write(['users' => $users]);
}
public function clearRememberToken(string $username): void
{
$normalized = normalize_username($username);
$users = $this->all();
$updated = false;
foreach ($users as &$user) {
if (($user['username'] ?? '') !== $normalized || !array_key_exists('remember_token', $user)) {
continue;
}
unset($user['remember_token']);
$user['updated_at'] = date(DATE_ATOM);
$updated = true;
break;
}
unset($user);
if ($updated) {
$this->write(['users' => $users]);
}
}
public function findByHealthImportToken(string $token): ?array
{
$tokenHash = hash('sha256', $token);
foreach ($this->all() as $user) {
$config = $user['health_import'] ?? null;
if (!is_array($config) || empty($config['enabled'])) {
continue;
}
if (hash_equals((string) ($config['token_hash'] ?? ''), $tokenHash)) {
return $user;
}
}
return null;
}
public function healthImportConfig(string $username): array
{
$user = $this->find($username);
$config = is_array($user['health_import'] ?? null) ? $user['health_import'] : [];
return [
'enabled' => !empty($config['enabled']),
'token_prefix' => (string) ($config['token_prefix'] ?? ''),
'created_at' => (string) ($config['created_at'] ?? ''),
'last_import_at' => (string) ($config['last_import_at'] ?? ''),
'last_status' => (string) ($config['last_status'] ?? ''),
'last_message' => (string) ($config['last_message'] ?? ''),
'progress_done' => max(0, (int) ($config['progress_done'] ?? 0)),
'progress_total' => max(0, (int) ($config['progress_total'] ?? 0)),
'started_at' => (string) ($config['started_at'] ?? ''),
'updated_at' => (string) ($config['updated_at'] ?? ''),
'finished_at' => (string) ($config['finished_at'] ?? ''),
];
}
public function issueHealthImportToken(string $username): string
{
$token = 'mood_health_' . bin2hex(random_bytes(24));
$normalized = normalize_username($username);
$users = $this->all();
$updated = false;
foreach ($users as &$user) {
if (($user['username'] ?? '') !== $normalized) {
continue;
}
$currentConfig = is_array($user['health_import'] ?? null) ? $user['health_import'] : [];
$user['health_import'] = [
'enabled' => true,
'token_hash' => hash('sha256', $token),
'token_prefix' => substr($token, 0, 18),
'created_at' => date(DATE_ATOM),
'last_import_at' => (string) ($currentConfig['last_import_at'] ?? ''),
'last_status' => (string) ($currentConfig['last_status'] ?? ''),
'last_message' => (string) ($currentConfig['last_message'] ?? ''),
'progress_done' => max(0, (int) ($currentConfig['progress_done'] ?? 0)),
'progress_total' => max(0, (int) ($currentConfig['progress_total'] ?? 0)),
'started_at' => (string) ($currentConfig['started_at'] ?? ''),
'updated_at' => (string) ($currentConfig['updated_at'] ?? ''),
'finished_at' => (string) ($currentConfig['finished_at'] ?? ''),
];
$user['updated_at'] = date(DATE_ATOM);
$updated = true;
break;
}
unset($user);
if (!$updated) {
throw new RuntimeException('Der Health-Import-Token konnte keinem Benutzer zugeordnet werden.');
}
$this->write(['users' => $users]);
return $token;
}
public function revokeHealthImportToken(string $username): void
{
$normalized = normalize_username($username);
$users = $this->all();
$updated = false;
foreach ($users as &$user) {
if (($user['username'] ?? '') !== $normalized || !array_key_exists('health_import', $user)) {
continue;
}
unset($user['health_import']);
$user['updated_at'] = date(DATE_ATOM);
$updated = true;
break;
}
unset($user);
if ($updated) {
$this->write(['users' => $users]);
}
}
public function recordHealthImport(string $username, string $status, string $message): void
{
$normalized = normalize_username($username);
$users = $this->all();
$updated = false;
foreach ($users as &$user) {
if (($user['username'] ?? '') !== $normalized) {
continue;
}
$config = is_array($user['health_import'] ?? null) ? $user['health_import'] : [];
$config['last_import_at'] = date(DATE_ATOM);
$config['last_status'] = $status;
$config['last_message'] = substr($message, 0, 240);
$config['updated_at'] = date(DATE_ATOM);
if ($status !== 'running') {
$config['finished_at'] = date(DATE_ATOM);
if ($status === 'ok') {
$total = max(0, (int) ($config['progress_total'] ?? 0));
$config['progress_done'] = $total > 0 ? $total : max(0, (int) ($config['progress_done'] ?? 0));
}
}
$user['health_import'] = $config;
$user['updated_at'] = date(DATE_ATOM);
$updated = true;
break;
}
unset($user);
if ($updated) {
$this->write(['users' => $users]);
}
}
public function recordHealthImportProgress(string $username, string $message, int $done, int $total, ?string $startedAt = null): void
{
$normalized = normalize_username($username);
$users = $this->all();
$updated = false;
foreach ($users as &$user) {
if (($user['username'] ?? '') !== $normalized) {
continue;
}
$config = is_array($user['health_import'] ?? null) ? $user['health_import'] : [];
$config['last_status'] = 'running';
$config['last_message'] = substr($message, 0, 240);
$config['progress_done'] = max(0, min($done, max($total, 0)));
$config['progress_total'] = max(0, $total);
$config['started_at'] = $startedAt ?? (string) ($config['started_at'] ?? date(DATE_ATOM));
$config['updated_at'] = date(DATE_ATOM);
$config['finished_at'] = '';
$user['health_import'] = $config;
$user['updated_at'] = date(DATE_ATOM);
$updated = true;
break;
}
unset($user);
if ($updated) {
$this->write(['users' => $users]);
}
}
public function create(string $username, string $password, bool $isAdmin = false): array
{
$normalized = normalize_username($username);