Add facilities, contracts, orders, value lists, audit log, and desktop app modules
Extends omsorgCore with full CRUD for Facility/Contract/Order plus configurable value lists and an audit trail, and wires the omsorgapp frontend up to the new facilities, settings, and audit-log modules; includes a sidebar active-nav-item highlight. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ee74ed65f5
commit
e9e96a57dc
@@ -3,6 +3,13 @@ require_once __DIR__ . '/../lib/auth.php';
|
||||
require_once __DIR__ . '/../lib/layout.php';
|
||||
require_login();
|
||||
|
||||
// Nach Direct-Anlage/Admin-Reset muss zuerst ein eigenes Passwort gesetzt werden, bevor es
|
||||
// weitergeht (Flag kommt aus der Login-Response, siehe _apply_token_pair in lib/auth.php).
|
||||
if (!empty($_SESSION['omsorgcore_must_change_password'])) {
|
||||
header('Location: settings.php?forced=1');
|
||||
exit;
|
||||
}
|
||||
|
||||
layout_start('Dashboard – Mitarbeiter-App');
|
||||
?>
|
||||
<h1 class="main-title">Willkommen, <span><?= e(current_name()) ?></span></h1>
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../lib/auth.php';
|
||||
|
||||
if (is_logged_in()) {
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$policy = omsorgcore_password_policy(_omsorgcore_config());
|
||||
$minLength = $policy['ok'] ? (int) $policy['data']['minLength'] : 8;
|
||||
|
||||
$step = $_POST['step'] ?? 'request';
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
verify_csrf();
|
||||
|
||||
if ($step === 'request') {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
if ($username === '') {
|
||||
$error = 'Bitte Benutzername eingeben.';
|
||||
} else {
|
||||
omsorgcore_forgot_password_request(_omsorgcore_config(), $username);
|
||||
// Bewusst immer weiter zu Schritt 2, unabhängig vom Ergebnis - kein Rückschluss darauf,
|
||||
// ob der Username existiert (siehe PasswordResetService.RequestResetAsync in omsorgCore).
|
||||
$step = 'verify';
|
||||
}
|
||||
} elseif ($step === 'verify') {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$pin = trim($_POST['pin'] ?? '');
|
||||
$result = omsorgcore_forgot_password_verify(_omsorgcore_config(), $username, $pin);
|
||||
|
||||
if ($result['ok']) {
|
||||
$resetToken = $result['data']['resetToken'];
|
||||
$step = 'reset';
|
||||
} else {
|
||||
$error = 'Code ungültig oder abgelaufen.';
|
||||
}
|
||||
} elseif ($step === 'reset') {
|
||||
$resetToken = $_POST['reset_token'] ?? '';
|
||||
$new = $_POST['new_password'] ?? '';
|
||||
$repeat = $_POST['new_password_repeat'] ?? '';
|
||||
|
||||
if (strlen($new) < $minLength) {
|
||||
$error = "Das neue Passwort muss mindestens {$minLength} Zeichen lang sein.";
|
||||
} elseif ($new !== $repeat) {
|
||||
$error = 'Die Passwörter stimmen nicht überein.';
|
||||
} else {
|
||||
$result = omsorgcore_forgot_password_reset(_omsorgcore_config(), $resetToken, $new);
|
||||
if ($result['ok']) {
|
||||
header('Location: ../index.php?pwchanged=1');
|
||||
exit;
|
||||
}
|
||||
$error = $result['status'] === 400 && is_string($result['data'] ?? null)
|
||||
? $result['data']
|
||||
: 'Zurücksetzen fehlgeschlagen. Bitte Vorgang erneut starten.';
|
||||
if ($result['status'] !== 400) {
|
||||
$step = 'request';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>OMSORG Mitarbeiter-App – Passwort vergessen</title>
|
||||
<link rel="stylesheet" href="../app.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="login-page">
|
||||
<div class="login-card glass">
|
||||
<h2 style="font-family:'KindelSerif',Georgia,serif;font-size:1.5rem;margin:0 0 6px">Passwort vergessen</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="error" style="margin-bottom:16px"><?= e($error) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($step === 'request'): ?>
|
||||
<p class="hint" style="margin:0 0 22px">Gib deinen Benutzernamen ein, wir senden dir einen Code per E-Mail.</p>
|
||||
<form method="post">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="step" value="request">
|
||||
<label>
|
||||
Benutzername
|
||||
<input type="text" name="username" autocomplete="username" required autofocus>
|
||||
</label>
|
||||
<button type="submit" class="btn" style="width:100%;margin-top:6px">Code anfordern</button>
|
||||
</form>
|
||||
|
||||
<?php elseif ($step === 'verify'): ?>
|
||||
<p class="hint" style="margin:0 0 22px">Gib den Code ein, den wir dir per E-Mail geschickt haben.</p>
|
||||
<form method="post">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="step" value="verify">
|
||||
<input type="hidden" name="username" value="<?= e($username ?? '') ?>">
|
||||
<label>
|
||||
Code
|
||||
<input type="text" name="pin" inputmode="numeric" pattern="[0-9]*" maxlength="6" required autofocus>
|
||||
</label>
|
||||
<button type="submit" class="btn" style="width:100%;margin-top:6px">Code bestätigen</button>
|
||||
</form>
|
||||
|
||||
<?php elseif ($step === 'reset'): ?>
|
||||
<p class="hint" style="margin:0 0 22px">Lege dein neues Passwort fest.</p>
|
||||
<form method="post">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="step" value="reset">
|
||||
<input type="hidden" name="reset_token" value="<?= e($resetToken ?? '') ?>">
|
||||
<label>
|
||||
Neues Passwort
|
||||
<input type="password" name="new_password" autocomplete="new-password" required minlength="<?= (int) $minLength ?>" autofocus>
|
||||
</label>
|
||||
<label>
|
||||
Neues Passwort wiederholen
|
||||
<input type="password" name="new_password_repeat" autocomplete="new-password" required minlength="<?= (int) $minLength ?>">
|
||||
</label>
|
||||
<button type="submit" class="btn" style="width:100%;margin-top:6px">Passwort setzen</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="hint" style="text-align:center;margin-top:14px">
|
||||
<a href="../index.php">Zurück zum Login</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../lib/auth.php';
|
||||
require_once __DIR__ . '/../lib/layout.php';
|
||||
require_login();
|
||||
|
||||
$forced = isset($_GET['forced']);
|
||||
$error = '';
|
||||
$policy = omsorgcore_password_policy(_omsorgcore_config());
|
||||
$minLength = $policy['ok'] ? (int) $policy['data']['minLength'] : 8;
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
verify_csrf();
|
||||
|
||||
$current = $_POST['current_password'] ?? '';
|
||||
$new = $_POST['new_password'] ?? '';
|
||||
$repeat = $_POST['new_password_repeat'] ?? '';
|
||||
|
||||
if (strlen($new) < $minLength) {
|
||||
$error = "Das neue Passwort muss mindestens {$minLength} Zeichen lang sein.";
|
||||
} elseif ($new !== $repeat) {
|
||||
$error = 'Die Passwörter stimmen nicht überein.';
|
||||
} else {
|
||||
$result = omsorgcore_change_password(_omsorgcore_config(), $_SESSION['omsorgcore_access_token'], $current, $new);
|
||||
|
||||
if ($result['ok']) {
|
||||
// Erfolgreicher Wechsel widerruft serverseitig alle Sessions (siehe
|
||||
// UserService.ChangeOwnPasswordAsync) - lokal ausloggen statt weiterzumachen.
|
||||
$_SESSION = [];
|
||||
if (ini_get('session.use_cookies')) {
|
||||
$p = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], $p['secure'], $p['httponly']);
|
||||
}
|
||||
session_destroy();
|
||||
header('Location: ../index.php?pwchanged=1');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = $result['status'] === 401
|
||||
? 'Aktuelles Passwort ist falsch.'
|
||||
: (is_string($result['data'] ?? null) ? $result['data'] : 'Passwort konnte nicht geändert werden.');
|
||||
}
|
||||
}
|
||||
|
||||
layout_start('Einstellungen – Mitarbeiter-App', 'settings');
|
||||
?>
|
||||
<h1 class="main-title">Einstellungen</h1>
|
||||
|
||||
<?php if ($forced): ?>
|
||||
<p class="hint" style="margin:0 0 22px">Für diesen Account wurde ein initiales Passwort vergeben. Bitte lege jetzt dein eigenes Passwort fest, bevor du weiterarbeiten kannst.</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="glass" style="max-width:420px;padding:24px">
|
||||
<h2 style="font-family:'KindelSerif',Georgia,serif;font-size:1.3rem;margin:0 0 18px">Passwort ändern</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="error" style="margin-bottom:16px"><?= e($error) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post">
|
||||
<?= csrf_field() ?>
|
||||
<label>
|
||||
Aktuelles Passwort
|
||||
<input type="password" name="current_password" autocomplete="current-password" required autofocus>
|
||||
</label>
|
||||
<label>
|
||||
Neues Passwort
|
||||
<input type="password" name="new_password" autocomplete="new-password" required minlength="<?= (int) $minLength ?>">
|
||||
</label>
|
||||
<label>
|
||||
Neues Passwort wiederholen
|
||||
<input type="password" name="new_password_repeat" autocomplete="new-password" required minlength="<?= (int) $minLength ?>">
|
||||
</label>
|
||||
<button type="submit" class="btn" style="width:100%;margin-top:6px">Passwort ändern</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
layout_end();
|
||||
Reference in New Issue
Block a user