send
This commit is contained in:
@@ -1,3 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
redirect('/login');
|
||||||
|
}
|
||||||
|
?>
|
||||||
<main class="section">
|
<main class="section">
|
||||||
<div class="container" style="display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px;">
|
<div class="container" style="display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px;">
|
||||||
<div>
|
<div>
|
||||||
@@ -61,7 +66,7 @@
|
|||||||
<div class="card dash-card">
|
<div class="card dash-card">
|
||||||
<div class="badge">Eigenes Event</div>
|
<div class="badge">Eigenes Event</div>
|
||||||
<h3>Neuen Termin erstellen</h3>
|
<h3>Neuen Termin erstellen</h3>
|
||||||
<form class="stack gap-12" style="margin-top: 10px;">
|
<form class="stack gap-12" style="margin-top: 10px;" method="post" action="/dashboard#events">
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="stack gap-6">
|
<div class="stack gap-6">
|
||||||
<label class="label" for="evTitle">Titel</label>
|
<label class="label" for="evTitle">Titel</label>
|
||||||
|
|||||||
@@ -1,17 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
$app = app();
|
||||||
|
$flash = $app->flash()->get();
|
||||||
|
$isLoggedIn = isset($_SESSION['user_id']);
|
||||||
|
$error = '';
|
||||||
|
$emailPrefill = '';
|
||||||
|
|
||||||
|
if ($isLoggedIn) {
|
||||||
|
redirect('/dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$email = trim((string)($_POST['email'] ?? ''));
|
||||||
|
$emailPrefill = $email;
|
||||||
|
$password = (string)($_POST['password'] ?? '');
|
||||||
|
try {
|
||||||
|
$auth = new \App\Auth($app);
|
||||||
|
$userId = $auth->login($email, $password);
|
||||||
|
$_SESSION['user_id'] = $userId;
|
||||||
|
$app->flash()->set('success', 'Erfolgreich angemeldet.');
|
||||||
|
redirect('/dashboard');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$error = $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
<main class="auth-wrap">
|
<main class="auth-wrap">
|
||||||
<div class="container auth-grid">
|
<div class="container auth-grid">
|
||||||
<section class="card auth-card">
|
<section class="card auth-card">
|
||||||
<div class="badge">Login</div>
|
<div class="badge">Login</div>
|
||||||
<h1 class="mt-1" style="margin: 12px 0;">Willkommen zurück</h1>
|
<h1 class="mt-1" style="margin: 12px 0;">Willkommen zurück</h1>
|
||||||
<p class="muted">Melde dich an, um Events zu erstellen, teilzunehmen und dein Profil zu verwalten.</p>
|
<p class="muted">Melde dich an, um Events zu erstellen, teilzunehmen und dein Profil zu verwalten.</p>
|
||||||
<form class="stack gap-12" style="margin-top: 14px;">
|
<?php if ($flash): ?>
|
||||||
|
<div class="toast-bar" style="margin-top: 10px;"><?= htmlspecialchars($flash['message'], ENT_QUOTES) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="toast-bar" style="margin-top: 10px; border-color:#f87171; color:#991b1b;">Fehler: <?= htmlspecialchars($error, ENT_QUOTES) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form class="stack gap-12" style="margin-top: 14px;" method="post" action="/login">
|
||||||
<div class="stack gap-6">
|
<div class="stack gap-6">
|
||||||
<label class="label" for="loginEmail">E-Mail</label>
|
<label class="label" for="loginEmail">E-Mail</label>
|
||||||
<input id="loginEmail" name="email" class="input" type="email" required placeholder="du@example.com">
|
<input id="loginEmail" name="email" class="input" type="email" required placeholder="du@example.com" value="<?= htmlspecialchars($emailPrefill, ENT_QUOTES) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="stack gap-6">
|
<div class="stack gap-6">
|
||||||
<label class="label" for="loginPassword">Passwort</label>
|
<label class="label" for="loginPassword">Passwort</label>
|
||||||
<input id="loginPassword" name="password" class="input" type="password" required placeholder="********">
|
<input id="loginPassword" name="password" class="input" type="password" required placeholder="********" autocomplete="current-password">
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; flex-wrap: wrap; gap: 8px;">
|
<div style="display:flex; justify-content:space-between; align-items:center; flex-wrap: wrap; gap: 8px;">
|
||||||
<label style="display:flex; gap:8px; align-items:center; font-size:14px; color: var(--color-muted);">
|
<label style="display:flex; gap:8px; align-items:center; font-size:14px; color: var(--color-muted);">
|
||||||
|
|||||||
@@ -1,26 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
$app = app();
|
||||||
|
$flash = $app->flash()->get();
|
||||||
|
$isLoggedIn = isset($_SESSION['user_id']);
|
||||||
|
$error = '';
|
||||||
|
$displayName = '';
|
||||||
|
$email = '';
|
||||||
|
|
||||||
|
if ($isLoggedIn) {
|
||||||
|
redirect('/dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$displayName = trim((string)($_POST['display_name'] ?? ''));
|
||||||
|
$email = trim((string)($_POST['email'] ?? ''));
|
||||||
|
$password = (string)($_POST['password'] ?? '');
|
||||||
|
$password2 = (string)($_POST['password_confirm'] ?? '');
|
||||||
|
|
||||||
|
if ($password !== $password2) {
|
||||||
|
$error = 'Passwörter stimmen nicht überein.';
|
||||||
|
} elseif (strlen($password) < 8) {
|
||||||
|
$error = 'Passwort muss mindestens 8 Zeichen haben.';
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$auth = new \App\Auth($app);
|
||||||
|
$userId = $auth->register($displayName, $email, $password);
|
||||||
|
$_SESSION['user_id'] = $userId;
|
||||||
|
$app->flash()->set('success', 'Willkommen! Dein Account wurde erstellt.');
|
||||||
|
redirect('/dashboard');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$error = $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
<main class="auth-wrap">
|
<main class="auth-wrap">
|
||||||
<div class="container auth-grid">
|
<div class="container auth-grid">
|
||||||
<section class="card auth-card">
|
<section class="card auth-card">
|
||||||
<div class="badge">Registrierung</div>
|
<div class="badge">Registrierung</div>
|
||||||
<h1 class="mt-1" style="margin: 12px 0;">Jetzt Account anlegen</h1>
|
<h1 class="mt-1" style="margin: 12px 0;">Jetzt Account anlegen</h1>
|
||||||
<p class="muted">Registriere dich mit wenigen Angaben. Alles Weitere pflegst du später im Mitgliederbereich.</p>
|
<p class="muted">Registriere dich mit wenigen Angaben. Alles Weitere pflegst du später im Mitgliederbereich.</p>
|
||||||
<form class="stack gap-12" style="margin-top: 14px;">
|
<?php if ($flash): ?>
|
||||||
|
<div class="toast-bar" style="margin-top: 10px;"><?= htmlspecialchars($flash['message'], ENT_QUOTES) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="toast-bar" style="margin-top: 10px; border-color:#f87171; color:#991b1b;">Fehler: <?= htmlspecialchars($error, ENT_QUOTES) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form class="stack gap-12" style="margin-top: 14px;" method="post" action="/register">
|
||||||
<div class="stack gap-6">
|
<div class="stack gap-6">
|
||||||
<label class="label" for="regName">Anzeigename</label>
|
<label class="label" for="regName">Anzeigename</label>
|
||||||
<input id="regName" name="display_name" class="input" required placeholder="z. B. Papa Alex">
|
<input id="regName" name="display_name" class="input" required placeholder="z. B. Papa Alex" value="<?= htmlspecialchars($displayName ?? '', ENT_QUOTES) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="stack gap-6">
|
<div class="stack gap-6">
|
||||||
<label class="label" for="regEmail">E-Mail</label>
|
<label class="label" for="regEmail">E-Mail</label>
|
||||||
<input id="regEmail" name="email" class="input" type="email" required placeholder="du@example.com">
|
<input id="regEmail" name="email" class="input" type="email" required placeholder="du@example.com" value="<?= htmlspecialchars($email ?? '', ENT_QUOTES) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="stack gap-6">
|
<div class="stack gap-6">
|
||||||
<label class="label" for="regPassword">Passwort</label>
|
<label class="label" for="regPassword">Passwort</label>
|
||||||
<input id="regPassword" name="password" class="input" type="password" required placeholder="********">
|
<input id="regPassword" name="password" class="input" type="password" required placeholder="********" autocomplete="new-password">
|
||||||
</div>
|
</div>
|
||||||
<div class="stack gap-6">
|
<div class="stack gap-6">
|
||||||
<label class="label" for="regPassword2">Passwort bestätigen</label>
|
<label class="label" for="regPassword2">Passwort bestätigen</label>
|
||||||
<input id="regPassword2" name="password_confirm" class="input" type="password" required placeholder="********">
|
<input id="regPassword2" name="password_confirm" class="input" type="password" required placeholder="********" autocomplete="new-password">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn block" type="submit">Account erstellen</button>
|
<button class="btn block" type="submit">Account erstellen</button>
|
||||||
|
|||||||
88
src/App/Auth.php
Normal file
88
src/App/Auth.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
final class Auth
|
||||||
|
{
|
||||||
|
public function __construct(private App $app) {}
|
||||||
|
|
||||||
|
private function pdo(): \PDO
|
||||||
|
{
|
||||||
|
$pdo = $this->app->pdo();
|
||||||
|
if (!$pdo) {
|
||||||
|
throw new \RuntimeException('Database connection not available.');
|
||||||
|
}
|
||||||
|
return $pdo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function register(string $displayName, string $email, string $password): int
|
||||||
|
{
|
||||||
|
$pdo = $this->pdo();
|
||||||
|
$email = strtolower(trim($email));
|
||||||
|
$displayName = trim($displayName);
|
||||||
|
|
||||||
|
if ($displayName === '' || $email === '' || $password === '') {
|
||||||
|
throw new \InvalidArgumentException('Display-Name, E-Mail und Passwort sind erforderlich.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare('SELECT id FROM users WHERE email = :email LIMIT 1');
|
||||||
|
$stmt->execute(['email' => $email]);
|
||||||
|
if ($stmt->fetchColumn()) {
|
||||||
|
throw new \RuntimeException('E-Mail ist bereits registriert.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash = password_hash($password, PASSWORD_ARGON2ID);
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO users (email, password_hash, status, created_at, updated_at) VALUES (:email, :pw, :status, NOW(), NOW())');
|
||||||
|
$stmt->execute([
|
||||||
|
'email' => $email,
|
||||||
|
'pw' => $hash,
|
||||||
|
'status' => 'active',
|
||||||
|
]);
|
||||||
|
$userId = (int)$pdo->lastInsertId();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO user_profiles (user_id, display_name, share_level, children_visibility, created_at, updated_at) VALUES (:uid, :name, :share, :childvis, NOW(), NOW())');
|
||||||
|
$stmt->execute([
|
||||||
|
'uid' => $userId,
|
||||||
|
'name' => $displayName,
|
||||||
|
'share' => 'basic',
|
||||||
|
'childvis' => 'hidden',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
return $userId;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(string $email, string $password): int
|
||||||
|
{
|
||||||
|
$pdo = $this->pdo();
|
||||||
|
$email = strtolower(trim($email));
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT id, password_hash, status FROM users WHERE email = :email LIMIT 1');
|
||||||
|
$stmt->execute(['email' => $email]);
|
||||||
|
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
throw new \RuntimeException('E-Mail oder Passwort ist falsch.');
|
||||||
|
}
|
||||||
|
if ($row['status'] !== 'active') {
|
||||||
|
throw new \RuntimeException('Account ist nicht aktiv.');
|
||||||
|
}
|
||||||
|
if (!password_verify($password, (string)$row['password_hash'])) {
|
||||||
|
throw new \RuntimeException('E-Mail oder Passwort ist falsch.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$userId = (int)$row['id'];
|
||||||
|
|
||||||
|
$upd = $pdo->prepare('UPDATE users SET last_login_at = NOW() WHERE id = :id');
|
||||||
|
$upd->execute(['id' => $userId]);
|
||||||
|
|
||||||
|
return $userId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -76,3 +76,9 @@ function asset_scripts(string $pos = 'footer'): void
|
|||||||
echo '<script src="' . htmlspecialchars($src, ENT_QUOTES) . '"' . $attrs . '></script>' . "\n";
|
echo '<script src="' . htmlspecialchars($src, ENT_QUOTES) . '"' . $attrs . '></script>' . "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function redirect(string $path): void
|
||||||
|
{
|
||||||
|
header('Location: ' . $path, true, 303);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user