Compare commits
8 Commits
1a85212265
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bdff6a033 | ||
|
|
9082218868 | ||
|
|
d45749316e | ||
|
|
acf49caefc | ||
|
|
7867afdaec | ||
|
|
61360c3e4c | ||
|
|
72f55b0aed | ||
|
|
0e5530b139 |
BIN
backups/DoMiLi_Backup_2025-11.pdf
Executable file
BIN
backups/DoMiLi_Backup_2025-11.pdf
Executable file
Binary file not shown.
BIN
backups/DoMiLi_Backup_2025-12.pdf
Executable file
BIN
backups/DoMiLi_Backup_2025-12.pdf
Executable file
Binary file not shown.
BIN
backups/DoMiLi_Backup_2026-01.pdf
Executable file
BIN
backups/DoMiLi_Backup_2026-01.pdf
Executable file
Binary file not shown.
@@ -28,13 +28,36 @@ if (!isset($_SESSION['user_id']) && isset($_COOKIE['remember_token'])) {
|
||||
$update_stmt = mysqli_prepare($conn, $update_sql);
|
||||
mysqli_stmt_bind_param($update_stmt, "ss", $new_expires_at, $token);
|
||||
mysqli_stmt_execute($update_stmt);
|
||||
mysqli_stmt_close($update_stmt);
|
||||
} else {
|
||||
// Token ist ungültig oder abgelaufen, Cookie löschen
|
||||
setcookie('remember_token', '', time() - 3600, "/");
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
// 🔹 Letzte Aktivität aktualisieren (nur für eingeloggte Benutzer)
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$now = new DateTime();
|
||||
$last_update = $_SESSION['last_activity_update'] ?? null;
|
||||
$update_needed = true;
|
||||
|
||||
if ($last_update) {
|
||||
$last = new DateTime($last_update);
|
||||
if ($now->getTimestamp() - $last->getTimestamp() < 60) {
|
||||
$update_needed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($update_needed) {
|
||||
$stmt = mysqli_prepare($conn, "UPDATE users SET last_activity = NOW() WHERE id = ?");
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, "i", $_SESSION['user_id']);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
$_SESSION['last_activity_update'] = $now->format('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
10
inc/menu.php
10
inc/menu.php
@@ -26,6 +26,16 @@
|
||||
<li><a class="dropdown-item d-flex align-items-center" href="stats.php"><span class="material-icons text-secondary me-2">bar_chart</span>Statistik</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link d-flex align-items-center" href="trip.php">
|
||||
<span class="material-symbols-outlined md-18 me-2" style="width: 24px;">trip</span> Ausflüge
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link d-flex align-items-center" href="mail.php">
|
||||
<span class="material-symbols-outlined md-18 me-2" style="width: 24px;">mail</span> Mail
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link d-flex align-items-center" href="vacation.php">
|
||||
<span class="material-icons md-18 me-2" style="width: 24px;">beach_access</span> Abwesenheiten
|
||||
|
||||
155
mail.php
Executable file
155
mail.php
Executable file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
include('inc/check_login.php');
|
||||
require_once('inc/db.php');
|
||||
|
||||
// Nur Admins dürfen Mails senden
|
||||
if ($_SESSION['role'] !== 'admin') {
|
||||
header("Location: index.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
define('APP_URL', 'https://domili.borgal.de');
|
||||
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
|
||||
function get_all_users($conn)
|
||||
{
|
||||
$stmt = mysqli_prepare($conn, "SELECT id, username FROM users ORDER BY username");
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
$users = [];
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$users[] = $row;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
return $users;
|
||||
}
|
||||
|
||||
// --- MAIL SENDEN ---
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||
$message = "PHPMailer nicht verfügbar.";
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
$subject = trim($_POST['subject'] ?? '');
|
||||
$body = trim($_POST['body'] ?? '');
|
||||
$recipient_ids = $_POST['recipients'] ?? [];
|
||||
|
||||
if (empty($subject) || empty($body)) {
|
||||
$message = "Betreff und Nachricht sind erforderlich.";
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
$all_users = get_all_users($conn);
|
||||
if (in_array('all', $recipient_ids)) {
|
||||
$recipient_ids = array_column($all_users, 'id');
|
||||
} else {
|
||||
$recipient_ids = array_filter(array_map('intval', $recipient_ids));
|
||||
}
|
||||
|
||||
if (empty($recipient_ids)) {
|
||||
$message = "Keine Empfänger ausgewählt.";
|
||||
$message_type = 'warning';
|
||||
} else {
|
||||
$placeholders = str_repeat('?,', count($recipient_ids) - 1) . '?';
|
||||
$stmt = mysqli_prepare($conn, "SELECT id, username, email FROM users WHERE id IN ($placeholders) AND email IS NOT NULL AND email != ''");
|
||||
mysqli_stmt_bind_param($stmt, str_repeat('i', count($recipient_ids)), ...$recipient_ids);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$recipients = mysqli_fetch_all(mysqli_stmt_get_result($stmt), MYSQLI_ASSOC);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
if (empty($recipients)) {
|
||||
$message = "Keine gültigen Empfänger mit E-Mail gefunden.";
|
||||
$message_type = 'warning';
|
||||
} else {
|
||||
foreach ($recipients as $r) {
|
||||
try {
|
||||
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->isSMTP();
|
||||
$mail->Host = SMTP_HOST;
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = SMTP_USERNAME;
|
||||
$mail->Password = SMTP_PASSWORD;
|
||||
$mail->SMTPSecure = SMTP_ENCRYPTION;
|
||||
$mail->Port = SMTP_PORT;
|
||||
$mail->setFrom(MAIL_FROM_ADDRESS, MAIL_FROM_NAME);
|
||||
|
||||
$html_body = "<p>Hallo <strong>" . htmlspecialchars($r['username']) . "</strong>,</p>\n<p>" . nl2br(htmlspecialchars($body)) . "</p>\n<p><em>Dein DoMiLi-Admin</em></p>";
|
||||
$text_body = "Hallo " . $r['username'] . ",\n\n" . $body . "\n\nDein DoMiLi-Admin";
|
||||
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = $subject;
|
||||
$mail->Body = $html_body;
|
||||
$mail->AltBody = $text_body;
|
||||
$mail->addAddress($r['email']);
|
||||
$mail->send();
|
||||
} catch (Exception $e) {
|
||||
error_log("Mail-Fehler an {$r['email']}: " . $mail->ErrorInfo);
|
||||
}
|
||||
}
|
||||
$message = "E-Mail wurde an " . count($recipients) . " Empfänger gesendet.";
|
||||
$message_type = 'success';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$all_users = get_all_users($conn);
|
||||
|
||||
require_once('inc/header.php');
|
||||
?>
|
||||
|
||||
<div class="container mt-5 mb-4">
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-<?= htmlspecialchars($message_type) ?> alert-dismissible fade show" role="alert">
|
||||
<?= htmlspecialchars($message) ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2 class="mb-4">📧 Nachricht senden</h2>
|
||||
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<form method="POST">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Empfänger</label>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="select_all" onchange="document.querySelectorAll('.recipient').forEach(el => el.checked = this.checked)">
|
||||
<label class="form-check-label" for="select_all">Alle auswählen</label>
|
||||
</div>
|
||||
<div style="max-height: 150px; overflow-y: auto; border: 1px solid #ddd; padding: 0.5em; border-radius: 0.375rem;">
|
||||
<?php foreach ($all_users as $u): ?>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input recipient" type="checkbox" name="recipients[]" value="<?= $u['id'] ?>" id="rec_<?= $u['id'] ?>">
|
||||
<label class="form-check-label" for="rec_<?= $u['id'] ?>"><?= htmlspecialchars($u['username']) ?></label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Betreff</label>
|
||||
<input type="text" class="form-control" name="subject" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nachricht</label>
|
||||
<textarea class="form-control" name="body" rows="5" required></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">E-Mail senden</button>
|
||||
<a href="javascript:history.back()" class="btn btn-outline-secondary ms-2">Zurück</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('select_all').addEventListener('change', function() {
|
||||
document.querySelectorAll('.recipient').forEach(cb => cb.checked = this.checked);
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include('inc/footer.php'); ?>
|
||||
402
trip.php
Executable file
402
trip.php
Executable file
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
include('inc/check_login.php');
|
||||
require_once('inc/db.php');
|
||||
|
||||
define('APP_URL', 'https://domili.borgal.de');
|
||||
|
||||
$is_admin = ($_SESSION['role'] === 'admin');
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
|
||||
if (isset($_SESSION['message'])) {
|
||||
$message = $_SESSION['message'];
|
||||
$message_type = $_SESSION['message_type'];
|
||||
unset($_SESSION['message'], $_SESSION['message_type']);
|
||||
}
|
||||
|
||||
function get_all_users($conn)
|
||||
{
|
||||
$stmt = mysqli_prepare($conn, "SELECT id, username FROM users ORDER BY username");
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
$users = [];
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$users[] = $row;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
return $users;
|
||||
}
|
||||
|
||||
function get_trip_groups($conn, $trip_id)
|
||||
{
|
||||
$stmt = mysqli_prepare($conn, "
|
||||
SELECT tg.driver_id, d.username AS driver_name,
|
||||
tg.passenger_id, p.username AS passenger_name,
|
||||
tg.notes
|
||||
FROM trip_groups tg
|
||||
JOIN users d ON tg.driver_id = d.id
|
||||
JOIN users p ON tg.passenger_id = p.id
|
||||
WHERE tg.trip_id = ?
|
||||
ORDER BY d.username, p.username
|
||||
");
|
||||
mysqli_stmt_bind_param($stmt, "i", $trip_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
$groups = [];
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$groups[] = $row;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
return $groups;
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['action']) && $_POST['action'] === 'save_trip') {
|
||||
$trip_id = !empty($_POST['trip_id']) ? (int)$_POST['trip_id'] : null;
|
||||
$title = trim($_POST['title'] ?? '');
|
||||
$description = trim($_POST['description'] ?? '');
|
||||
$hotel = trim($_POST['hotel'] ?? '');
|
||||
$hotel_address = trim($_POST['hotel_address'] ?? '');
|
||||
$start_date = trim($_POST['start_date'] ?? '');
|
||||
$end_date = trim($_POST['end_date'] ?? '');
|
||||
|
||||
if (empty($title) || empty($start_date) || empty($end_date)) {
|
||||
$_SESSION['message'] = "Titel, Start- und Enddatum sind erforderlich.";
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
$message = $_SESSION['message'];
|
||||
$message_type = $_SESSION['message_type'];
|
||||
} elseif (strtotime($start_date) > strtotime($end_date)) {
|
||||
$_SESSION['message'] = "Startdatum darf nicht nach dem Enddatum liegen.";
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
$message = $_SESSION['message'];
|
||||
$message_type = $_SESSION['message_type'];
|
||||
} else {
|
||||
mysqli_autocommit($conn, false);
|
||||
$success = false;
|
||||
|
||||
if ($trip_id) {
|
||||
$stmt = mysqli_prepare($conn, "UPDATE trips SET title = ?, description = ?, hotel = ?, hotel_address = ?, start_date = ?, end_date = ? WHERE id = ?");
|
||||
mysqli_stmt_bind_param($stmt, "ssssssi", $title, $description, $hotel, $hotel_address, $start_date, $end_date, $trip_id);
|
||||
} else {
|
||||
$stmt = mysqli_prepare($conn, "INSERT INTO trips (title, description, hotel, hotel_address, start_date, end_date) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
mysqli_stmt_bind_param($stmt, "ssssss", $title, $description, $hotel, $hotel_address, $start_date, $end_date);
|
||||
}
|
||||
|
||||
if (mysqli_stmt_execute($stmt)) {
|
||||
if (!$trip_id) {
|
||||
$trip_id = mysqli_insert_id($conn);
|
||||
}
|
||||
|
||||
mysqli_query($conn, "DELETE FROM trip_groups WHERE trip_id = $trip_id");
|
||||
|
||||
$drivers = $_POST['drivers'] ?? [];
|
||||
foreach ($drivers as $driver_id => $passengers) {
|
||||
$driver_id = (int)$driver_id;
|
||||
if (!empty($passengers['list'])) {
|
||||
foreach ($passengers['list'] as $passenger_id) {
|
||||
$passenger_id = (int)$passenger_id;
|
||||
if ($driver_id !== $passenger_id) {
|
||||
$notes = trim($passengers['notes'][$passenger_id] ?? '');
|
||||
$stmt_ins = mysqli_prepare($conn, "INSERT INTO trip_groups (trip_id, driver_id, passenger_id, notes) VALUES (?, ?, ?, ?)");
|
||||
mysqli_stmt_bind_param($stmt_ins, "iiis", $trip_id, $driver_id, $passenger_id, $notes);
|
||||
mysqli_stmt_execute($stmt_ins);
|
||||
mysqli_stmt_close($stmt_ins);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$success = true;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
if ($success) {
|
||||
mysqli_commit($conn);
|
||||
$_SESSION['message'] = $trip_id ? "Reise aktualisiert!" : "Neue Reise erstellt!";
|
||||
$_SESSION['message_type'] = 'success';
|
||||
header("Location: trip.php");
|
||||
exit();
|
||||
} else {
|
||||
mysqli_rollback($conn);
|
||||
$_SESSION['message'] = "Fehler beim Speichern der Reise.";
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
$message = $_SESSION['message'];
|
||||
$message_type = $_SESSION['message_type'];
|
||||
}
|
||||
mysqli_autocommit($conn, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['trip_id'])) {
|
||||
$trip_id = (int)$_GET['trip_id'];
|
||||
$stmt = mysqli_prepare($conn, "DELETE FROM trips WHERE id = ?");
|
||||
mysqli_stmt_bind_param($stmt, "i", $trip_id);
|
||||
if (mysqli_stmt_execute($stmt)) {
|
||||
$_SESSION['message'] = "Reise gelöscht!";
|
||||
$_SESSION['message_type'] = 'success';
|
||||
} else {
|
||||
$_SESSION['message'] = "Fehler beim Löschen.";
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
header("Location: trip.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$trips = [];
|
||||
$result = mysqli_query($conn, "SELECT * FROM trips ORDER BY start_date DESC");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$row['groups'] = get_trip_groups($conn, $row['id']);
|
||||
$trips[] = $row;
|
||||
}
|
||||
|
||||
$edit_trip = null;
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['trip_id'])) {
|
||||
$trip_id = (int)$_GET['trip_id'];
|
||||
$stmt = mysqli_prepare($conn, "SELECT * FROM trips WHERE id = ?");
|
||||
mysqli_stmt_bind_param($stmt, "i", $trip_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$edit_trip = mysqli_fetch_assoc(mysqli_stmt_get_result($stmt));
|
||||
mysqli_stmt_close($stmt);
|
||||
if ($edit_trip) {
|
||||
$edit_trip['groups'] = get_trip_groups($conn, $trip_id);
|
||||
$grouped = [];
|
||||
foreach ($edit_trip['groups'] as $g) {
|
||||
$grouped[$g['driver_id']][$g['passenger_id']] = $g['notes'];
|
||||
}
|
||||
$edit_trip['grouped'] = $grouped;
|
||||
}
|
||||
}
|
||||
|
||||
$all_users = get_all_users($conn);
|
||||
|
||||
require_once('inc/header.php');
|
||||
?>
|
||||
|
||||
<div class="container mt-5 mb-4">
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-<?= htmlspecialchars($message_type) ?> alert-dismissible fade show" role="alert">
|
||||
<?= htmlspecialchars($message) ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2 class="mb-4">🧳 Gemeinsame Reisen</h2>
|
||||
|
||||
<?php if ($is_admin): ?>
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header bg-primary-subtle text-secondary d-flex justify-content-between align-items-center">
|
||||
<h4 class="mb-0"><?= $edit_trip ? 'Reise bearbeiten' : 'Neue Reise anlegen' ?></h4>
|
||||
<?php if (!$edit_trip): ?>
|
||||
<a class="btn btn-sm d-flex align-items-center justify-content-center"
|
||||
data-bs-toggle="collapse" href="#tripFormCollapse" role="button" aria-expanded="false" aria-controls="tripFormCollapse">
|
||||
Add
|
||||
<span class="material-symbols-outlined ms-1">add</span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="collapse <?= $edit_trip ? 'show' : '' ?>" id="tripFormCollapse">
|
||||
<div class="card card-body bg-light">
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="save_trip">
|
||||
<?php if ($edit_trip): ?>
|
||||
<input type="hidden" name="trip_id" value="<?= $edit_trip['id'] ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Reisetitel *</label>
|
||||
<input type="text" class="form-control" name="title" value="<?= htmlspecialchars($edit_trip['title'] ?? '') ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Hotel</label>
|
||||
<input type="text" class="form-control" name="hotel" value="<?= htmlspecialchars($edit_trip['hotel'] ?? '') ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Hoteladresse</label>
|
||||
<textarea class="form-control" name="hotel_address" rows="2" placeholder="Straße, PLZ Ort, Land"><?= htmlspecialchars($edit_trip['hotel_address'] ?? '') ?></textarea>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Von *</label>
|
||||
<input type="date" class="form-control" name="start_date" value="<?= htmlspecialchars($edit_trip['start_date'] ?? date('Y-m-d')) ?>" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Bis *</label>
|
||||
<input type="date" class="form-control" name="end_date" value="<?= htmlspecialchars($edit_trip['end_date'] ?? '') ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Beschreibung</label>
|
||||
<textarea class="form-control" name="description" rows="2"><?= htmlspecialchars($edit_trip['description'] ?? '') ?></textarea>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4 mb-3">🚗 Fahrer und Mitfahrer</h5>
|
||||
<?php foreach ($all_users as $driver): ?>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input driver-checkbox" type="checkbox" id="driver_<?= $driver['id'] ?>"
|
||||
onchange="togglePassengerSection(<?= $driver['id'] ?>)"
|
||||
<?= (isset($edit_trip['grouped'][$driver['id']]) || (!empty($_POST) && isset($_POST['drivers'][$driver['id']]))) ? 'checked' : '' ?>>
|
||||
<label class="form-check-label" for="driver_<?= $driver['id'] ?>">
|
||||
<strong><?= htmlspecialchars($driver['username']) ?></strong> (Fahrer)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body <?= (!isset($edit_trip['grouped'][$driver['id']]) && empty($_POST)) ? 'd-none' : '' ?>" id="passengers_<?= $driver['id'] ?>">
|
||||
<div class="row">
|
||||
<?php foreach ($all_users as $passenger): ?>
|
||||
<?php if ($passenger['id'] == $driver['id']) continue; ?>
|
||||
<div class="col-md-6 mb-2">
|
||||
<div class="input-group">
|
||||
<div class="form-check me-2 mt-1">
|
||||
<input class="form-check-input passenger-checkbox" type="checkbox"
|
||||
name="drivers[<?= $driver['id'] ?>][list][]"
|
||||
value="<?= $passenger['id'] ?>"
|
||||
id="p_<?= $driver['id'] ?>_<?= $passenger['id'] ?>"
|
||||
<?= (isset($edit_trip['grouped'][$driver['id']][$passenger['id']]) || (!empty($_POST) && in_array($passenger['id'], $_POST['drivers'][$driver['id']]['list'] ?? []))) ? 'checked' : '' ?>>
|
||||
<label class="form-check-label" for="p_<?= $driver['id'] ?>_<?= $passenger['id'] ?>">
|
||||
<?= htmlspecialchars($passenger['username']) ?>
|
||||
</label>
|
||||
</div>
|
||||
<input type="text" class="form-control form-control-sm"
|
||||
placeholder="Notizen"
|
||||
name="drivers[<?= $driver['id'] ?>][notes][<?= $passenger['id'] ?>]"
|
||||
value="<?= htmlspecialchars($edit_trip['grouped'][$driver['id']][$passenger['id']] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<div class="mt-3">
|
||||
<button type="submit" class="btn btn-sm btn-primary"><?= $edit_trip ? 'Speichern' : 'Erstellen' ?></button>
|
||||
<?php if ($edit_trip): ?>
|
||||
<a href="trip.php" class="btn btn-sm btn-outline-secondary">Abbrechen</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function togglePassengerSection(driverId) {
|
||||
const section = document.getElementById('passengers_' + driverId);
|
||||
const checkbox = document.getElementById('driver_' + driverId);
|
||||
if (checkbox.checked) {
|
||||
section.classList.remove('d-none');
|
||||
} else {
|
||||
section.classList.add('d-none');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 🔸 Bestehende Reisen -->
|
||||
<?php if (!empty($trips)): ?>
|
||||
<?php foreach ($trips as $trip): ?>
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header bg-light d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h5 class="mb-0"><?= htmlspecialchars($trip['title']) ?></h5>
|
||||
<small class="text-muted">
|
||||
<?= date('d.m.Y', strtotime($trip['start_date'])) ?> – <?= date('d.m.Y', strtotime($trip['end_date'])) ?>
|
||||
</small>
|
||||
</div>
|
||||
<?php if ($is_admin): ?>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="text-secondary" data-bs-toggle="dropdown">
|
||||
<span class="material-icons">more_vert</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="trip.php?action=edit&trip_id=<?= $trip['id'] ?>"><span class="material-icons me-2">edit</span> Bearbeiten</a></li>
|
||||
<li><a class="dropdown-item text-danger" href="trip.php?action=delete&trip_id=<?= $trip['id'] ?>" onclick="return confirm('Wirklich löschen?')"><span class="material-icons me-2">delete</span> Löschen</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<?php
|
||||
$has_hotel = !empty($trip['hotel']) || !empty($trip['hotel_address']);
|
||||
$has_info = !empty($trip['description']);
|
||||
$has_driver = !empty($trip['groups']);
|
||||
?>
|
||||
|
||||
<!-- 🏨 Hotel -->
|
||||
<?php if ($has_hotel): ?>
|
||||
<h6 class="mt-0 mb-2"><strong>🏨 Hotel</strong></h6>
|
||||
<?php if (!empty($trip['hotel'])): ?>
|
||||
<p class="mb-1"><strong><?= htmlspecialchars($trip['hotel']) ?></strong></p>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($trip['hotel_address'])): ?>
|
||||
<p class="mb-2"><?= nl2br(htmlspecialchars($trip['hotel_address'])) ?></p>
|
||||
<?php
|
||||
$clean_address = preg_replace('/\s+/', ' ', trim(str_replace(["\r", "\n"], ' ', $trip['hotel_address'])));
|
||||
$maps_url = 'https://www.google.com/maps/search/?api=1&query=' . urlencode($clean_address);
|
||||
?>
|
||||
<a href="<?= htmlspecialchars($maps_url) ?>" target="_blank" class="btn btn-sm btn-outline-primary mt-1">
|
||||
<span class="material-icons me-1" style="font-size: 16px;">location_on</span>
|
||||
Auf Karte anzeigen
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Trennlinie, wenn danach Info oder Fahrer kommen -->
|
||||
<?php if ($has_info || $has_driver): ?>
|
||||
<hr class="my-3">
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ℹ️ Info -->
|
||||
<?php if ($has_info): ?>
|
||||
<h6 class="mb-2"><strong>ℹ️ Info</strong></h6>
|
||||
<p><?= nl2br(htmlspecialchars($trip['description'])) ?></p>
|
||||
|
||||
<!-- Trennlinie, wenn danach Fahrer kommen -->
|
||||
<?php if ($has_driver): ?>
|
||||
<hr class="my-3">
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 🚗 Fahrer -->
|
||||
<?php if ($has_driver): ?>
|
||||
<h6 class="mb-2"><strong>🚗 Fahrer</strong></h6>
|
||||
<?php
|
||||
$by_driver = [];
|
||||
foreach ($trip['groups'] as $g) {
|
||||
$by_driver[$g['driver_id']][] = $g;
|
||||
}
|
||||
?>
|
||||
<?php foreach ($by_driver as $driver_id => $passengers): ?>
|
||||
<p class="mb-1"><strong><?= htmlspecialchars($passengers[0]['driver_name']) ?></strong></p>
|
||||
<ul class="list-unstyled ms-3 mb-2">
|
||||
<?php foreach ($passengers as $p): ?>
|
||||
<li>
|
||||
<?= htmlspecialchars($p['passenger_name']) ?>
|
||||
<?php if (!empty($p['notes'])): ?>
|
||||
<br><small class="text-muted"><?= htmlspecialchars($p['notes']) ?></small>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<h6 class="mb-2 text-success"><strong>🚗 Fahrer</strong></h6>
|
||||
<p class="text-muted">Keine Fahrer/Mitfahrer eingetragen.</p>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="card shadow">
|
||||
<div class="card-body text-center text-muted py-4">
|
||||
<p>Keine Reisen geplant.</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php include('inc/footer.php'); ?>
|
||||
26
users.php
26
users.php
@@ -60,7 +60,7 @@ if ($is_admin && isset($_GET['action']) && $_GET['action'] == 'delete' && isset(
|
||||
// --- Nur Admins: Bearbeiten ---
|
||||
if ($is_admin && isset($_GET['action']) && $_GET['action'] == 'edit' && isset($_GET['id'])) {
|
||||
$id = (int)$_GET['id'];
|
||||
$stmt = mysqli_prepare($conn, "SELECT id, username, email, role, birthday FROM users WHERE id = ?");
|
||||
$stmt = mysqli_prepare($conn, "SELECT id, username, email, role, birthday, last_activity FROM users WHERE id = ?");
|
||||
mysqli_stmt_bind_param($stmt, "i", $id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
@@ -88,9 +88,6 @@ if ($is_admin && $_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$email = !empty($email_raw) ? $email_raw : null;
|
||||
$birthday_db = deDateToDb($birthday_de);
|
||||
|
||||
// --- DEBUG: Zeige, was konvertiert wurde (kannst du später löschen) ---
|
||||
// error_log("DEBUG: birthday_de='$birthday_de' → birthday_db='$birthday_db'");
|
||||
|
||||
if (empty($username)) {
|
||||
$message = "Benutzername ist erforderlich.";
|
||||
$message_type = 'danger';
|
||||
@@ -186,9 +183,9 @@ if ($is_admin && $_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Mitgliederliste ---
|
||||
// --- Mitgliederliste --- 🔹 last_activity hinzugefügt
|
||||
$users = [];
|
||||
$result = mysqli_query($conn, "SELECT id, username, role, email, birthday FROM users ORDER BY id ASC");
|
||||
$result = mysqli_query($conn, "SELECT id, username, role, email, birthday, last_activity FROM users ORDER BY id ASC");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$users[] = $row;
|
||||
}
|
||||
@@ -280,6 +277,7 @@ require_once 'inc/header.php';
|
||||
<th class="text-center" style="width: 56px;">Daten</th>
|
||||
<th>Rolle</th>
|
||||
<?php if ($is_admin): ?>
|
||||
<th class="text-center" style="width: 1px;"></th>
|
||||
<th class="text-end"></th>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
@@ -309,6 +307,22 @@ require_once 'inc/header.php';
|
||||
</span>
|
||||
</td>
|
||||
<?php if ($is_admin): ?>
|
||||
<!-- 🔹 Neue Status-Spalte -->
|
||||
<td class="text-center align-middle">
|
||||
<?php
|
||||
$is_online = !empty($user['last_activity']) && strtotime($user['last_activity']) >= strtotime('-10 minutes');
|
||||
$tooltip = $is_online
|
||||
? 'Online'
|
||||
: (!empty($user['last_activity'])
|
||||
? 'Zuletzt online: ' . date('d.m.Y H:i', strtotime($user['last_activity']))
|
||||
: 'Noch nie gesehen');
|
||||
$color = $is_online ? 'success' : 'secondary';
|
||||
?>
|
||||
<span
|
||||
class="badge rounded-pill bg-<?= $color ?> d-inline-block"
|
||||
title="<?= htmlspecialchars($tooltip) ?>"
|
||||
style="width: 12px; height: 12px; padding: 0; border: 1px solid #555;"></span>
|
||||
</td>
|
||||
<td class="text-end align-middle">
|
||||
<div class="dropdown">
|
||||
<a href="#" class="text-secondary" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
|
||||
83
vacation.php
83
vacation.php
@@ -51,9 +51,15 @@ if (isset($_GET['action']) && $_GET['action'] == 'delete' && isset($_GET['id']))
|
||||
}
|
||||
}
|
||||
|
||||
// --- Daten laden ---
|
||||
// --- Eigene Abwesenheiten (nur aktuell oder zukünftig) ---
|
||||
$vacations = [];
|
||||
$stmt = mysqli_prepare($conn, "SELECT id, start_date, end_date FROM vacations WHERE user_id = ? ORDER BY start_date DESC");
|
||||
$stmt = mysqli_prepare($conn, "
|
||||
SELECT id, start_date, end_date
|
||||
FROM vacations
|
||||
WHERE user_id = ?
|
||||
AND end_date >= CURDATE()
|
||||
ORDER BY start_date ASC
|
||||
");
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, "i", $logged_in_user_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
@@ -64,6 +70,38 @@ if ($stmt) {
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
|
||||
// --- Prüfen, ob Admin ---
|
||||
$is_admin = false;
|
||||
$stmt = mysqli_prepare($conn, "SELECT role FROM users WHERE id = ?");
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, "i", $logged_in_user_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
$user = mysqli_fetch_assoc($result);
|
||||
$is_admin = ($user && $user['role'] === 'admin');
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
|
||||
// --- Alle Abwesenheiten (nur aktuell oder zukünftig, nur für Admins) ---
|
||||
$all_vacations = [];
|
||||
if ($is_admin) {
|
||||
$stmt = mysqli_prepare($conn, "
|
||||
SELECT v.id, v.start_date, v.end_date, u.username
|
||||
FROM vacations v
|
||||
JOIN users u ON v.user_id = u.id
|
||||
WHERE v.end_date >= CURDATE()
|
||||
ORDER BY v.start_date ASC, u.username ASC
|
||||
");
|
||||
if ($stmt) {
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$all_vacations[] = $row;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
}
|
||||
|
||||
require_once 'inc/header.php';
|
||||
?>
|
||||
|
||||
@@ -79,6 +117,7 @@ require_once 'inc/header.php';
|
||||
<h2 class="mb-0">Abwesenheitsassistent</h2>
|
||||
</div>
|
||||
|
||||
<!-- Eigenen Urlaub eintragen -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header bg-primary-subtle text-secondary">
|
||||
<h4 class="mb-0">Urlaub eintragen</h4>
|
||||
@@ -103,13 +142,14 @@ require_once 'inc/header.php';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Eigene Abwesenheiten -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header bg-secondary bg-opacity-50 text-secondary">
|
||||
<h4 class="mb-0">Eingetragene Urlaube</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (empty($vacations)): ?>
|
||||
<p class="text-muted text-center">Es sind keine Urlaube eingetragen.</p>
|
||||
<p class="text-muted text-center">Es sind keine aktuellen oder zukünftigen Urlaube eingetragen.</p>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
@@ -132,7 +172,9 @@ require_once 'inc/header.php';
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<a class="dropdown-item d-flex align-items-center text-danger" href="vacation.php?action=delete&id=<?= htmlspecialchars($vacation['id']) ?>" onclick="return confirm('Wirklich löschen?')">
|
||||
<a class="dropdown-item d-flex align-items-center text-danger"
|
||||
href="vacation.php?action=delete&id=<?= htmlspecialchars($vacation['id']) ?>"
|
||||
onclick="return confirm('Wirklich löschen?')">
|
||||
<span class="material-icons me-2">delete_outline</span> Löschen
|
||||
</a>
|
||||
</li>
|
||||
@@ -147,6 +189,39 @@ require_once 'inc/header.php';
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alle Abwesenheiten (nur für Admins) -->
|
||||
<?php if ($is_admin && !empty($all_vacations)): ?>
|
||||
<div class="card shadow mt-4">
|
||||
<div class="card-header bg-info bg-opacity-25 text-dark">
|
||||
<h4 class="mb-0">Abwesenheiten aller Nutzer (aktuell & zukünftig)</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nutzer</th>
|
||||
<th>Zeitraum</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($all_vacations as $vac): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($vac['username']) ?></td>
|
||||
<td>
|
||||
Vom <?= date('d.m.Y', strtotime($vac['start_date'])) ?>
|
||||
bis <?= date('d.m.Y', strtotime($vac['end_date'])) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
|
||||
<?php include('inc/footer.php'); ?>
|
||||
@@ -356,6 +356,8 @@ require_once('inc/header.php');
|
||||
<?php if (empty($releases)): ?>
|
||||
<p class="text-muted">Keine veröffentlichten Release Notes vorhanden.</p>
|
||||
<?php else: ?>
|
||||
<?php $total = count($releases);
|
||||
$index = 0; ?>
|
||||
<?php foreach ($releases as $release): ?>
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="flex-grow-1">
|
||||
@@ -423,6 +425,11 @@ require_once('inc/header.php');
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($index < $total - 1): ?>
|
||||
<hr class="my-4">
|
||||
<?php endif; ?>
|
||||
<?php $index++; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user