Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
133b1d57ed | ||
|
|
1ad59a9881 | ||
|
|
c540d06939 | ||
|
|
52c11cc1b9 | ||
|
|
37fa819e97 | ||
|
|
6922bfa99b | ||
|
|
ce9fe75e9c | ||
|
|
8bccdddebe | ||
|
|
1228eccf52 | ||
|
|
973aa67153 | ||
|
|
a84b13a5c2 | ||
|
|
5ebed74e12 | ||
|
|
b80e44fd32 |
No files matched your search
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
// reset_einkaufsliste.php
|
||||
// Aufruf z.B. per Cron: php /pfad/zu/reset_einkaufsliste.php
|
||||
|
||||
include_once(__DIR__ . '/../controller/DatabaseController.php');
|
||||
|
||||
$result = DatabaseUpdate(
|
||||
'Einkaufsliste',
|
||||
'`STATUS` = ?',
|
||||
'`TYP` = ? AND `STATUS` = ?',
|
||||
'aktiv', 'vorlage', 'erledigt'
|
||||
);
|
||||
|
||||
echo $result
|
||||
? "Vorlagen-Artikel wurden zurückgesetzt.\n"
|
||||
: "Fehler beim Zurücksetzen.\n";
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
session_set_cookie_params([
|
||||
'lifetime' => 0,
|
||||
'path' => '/',
|
||||
'domain' => '',
|
||||
'secure' => false,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax'
|
||||
]);
|
||||
session_start();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '0');
|
||||
|
||||
if (empty($_SESSION['user_logged_in'])) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Nicht eingeloggt']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (empty($_SESSION['is_admin'])) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Keine Berechtigung']);
|
||||
exit;
|
||||
}
|
||||
|
||||
include_once(__DIR__ . '/../../../controller/DatabaseController.php');
|
||||
include_once(__DIR__ . '/../../../controller/NotifyController.php');
|
||||
|
||||
$daten = json_decode(file_get_contents('php://input'), true) ?? [];
|
||||
$action = $daten['action'] ?? '';
|
||||
|
||||
try {
|
||||
$notificationCtl = new Notification();
|
||||
|
||||
switch ($action) {
|
||||
|
||||
case 'get_entries': {
|
||||
$entries = $notificationCtl->getAllMessages();
|
||||
|
||||
foreach ($entries as &$entry) {
|
||||
$entry['GESEHEN_ANZAHL'] = $notificationCtl->countSeenBy((int)$entry['ID']);
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true, 'entries' => array_values($entries)]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'add_entry': {
|
||||
$titel = trim($daten['titel'] ?? '');
|
||||
$nachricht = trim($daten['nachricht'] ?? '');
|
||||
|
||||
if ($titel === '' || $nachricht === '') {
|
||||
throw new InvalidArgumentException('Titel und Nachricht erforderlich');
|
||||
}
|
||||
|
||||
$notificationCtl->createMessage($titel, $nachricht);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'edit_entry': {
|
||||
$id = $daten['id'] ?? null;
|
||||
$titel = trim($daten['titel'] ?? '');
|
||||
$nachricht = trim($daten['nachricht'] ?? '');
|
||||
|
||||
if (!is_numeric($id)) {
|
||||
throw new InvalidArgumentException('Ungültige ID');
|
||||
}
|
||||
if ($titel === '' || $nachricht === '') {
|
||||
throw new InvalidArgumentException('Titel und Nachricht erforderlich');
|
||||
}
|
||||
|
||||
$notificationCtl->updateMessage((int)$id, $titel, $nachricht);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'delete_entry': {
|
||||
$id = $daten['id'] ?? null;
|
||||
|
||||
if (!is_numeric($id)) {
|
||||
throw new InvalidArgumentException('Ungültige ID');
|
||||
}
|
||||
|
||||
$notificationCtl->deleteMessage((int)$id);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException("Unbekannte Aktion: $action");
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
} catch (Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(['error' => 'Serverfehler']);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
session_set_cookie_params([
|
||||
'lifetime' => 0,
|
||||
'path' => '/',
|
||||
'domain' => '',
|
||||
'secure' => false,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax'
|
||||
]);
|
||||
session_start();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '0');
|
||||
|
||||
if (empty($_SESSION['user_logged_in'])) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Nicht eingeloggt']);
|
||||
exit;
|
||||
}
|
||||
|
||||
include_once(__DIR__ . '/../../../controller/DatabaseController.php');
|
||||
include_once(__DIR__ . '/../../../controller/NotifyController.php');
|
||||
|
||||
$daten = json_decode(file_get_contents('php://input'), true) ?? [];
|
||||
$action = $daten['action'] ?? '';
|
||||
|
||||
try {
|
||||
switch ($action) {
|
||||
|
||||
case 'mark_seen': {
|
||||
$nachrichtId = $daten['nachricht_id'] ?? null;
|
||||
|
||||
if (!is_numeric($nachrichtId)) {
|
||||
throw new InvalidArgumentException('Ungültige Nachrichten-ID');
|
||||
}
|
||||
|
||||
$notificationCtl = new Notification();
|
||||
$notificationCtl->markAsSeen((int)$nachrichtId);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException("Unbekannte Aktion: $action");
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
} catch (Throwable $e) {
|
||||
http_response_code(500);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(['error' => 'Serverfehler']);
|
||||
}
|
||||
+1
-426
@@ -6,429 +6,4 @@ $superuser = array (
|
||||
'password' => 'bBHofurUJWKzPE8Z:',
|
||||
'active' => true,
|
||||
),
|
||||
);
|
||||
|
||||
$serviceGroups = array (
|
||||
'Info' =>
|
||||
array (
|
||||
'label' => 'Home',
|
||||
'defaultOpen' => true,
|
||||
'services' =>
|
||||
array (
|
||||
0 => 'home_info',
|
||||
1 => 'vergabe',
|
||||
2 => 'links',
|
||||
3 => 'einkaufsliste',
|
||||
4 => 'termine',
|
||||
5 => 'ticket_board',
|
||||
6 => 'ajaxTests',
|
||||
),
|
||||
),
|
||||
'Ausbildung' =>
|
||||
array (
|
||||
'label' => 'Ausbildung',
|
||||
'defaultOpen' => true,
|
||||
'services' =>
|
||||
array (
|
||||
0 => 'print_static',
|
||||
1 => 'zeiterfassung',
|
||||
2 => 'berichte_arbeit_gen',
|
||||
3 => 'berichte',
|
||||
4 => 'firmenberichte',
|
||||
5 => 'berufsschulberichte',
|
||||
),
|
||||
),
|
||||
'Logs' =>
|
||||
array (
|
||||
'label' => 'Webserver',
|
||||
'defaultOpen' => false,
|
||||
'services' =>
|
||||
array (
|
||||
0 => 'public_request_logs',
|
||||
1 => 'public_request_chart',
|
||||
2 => 'backend_request_logs',
|
||||
3 => 'backend_request_chart',
|
||||
4 => 'personal_request_logs',
|
||||
),
|
||||
),
|
||||
'System' =>
|
||||
array (
|
||||
'label' => 'Verwaltung',
|
||||
'defaultOpen' => false,
|
||||
'services' =>
|
||||
array (
|
||||
0 => 'data_info',
|
||||
1 => 'services_control',
|
||||
2 => 'user_control',
|
||||
3 => 'variablen_control',
|
||||
4 => 'ticket_control',
|
||||
),
|
||||
),
|
||||
'Test' =>
|
||||
array (
|
||||
'label' => 'Dev / Test',
|
||||
'defaultOpen' => false,
|
||||
'services' =>
|
||||
array (
|
||||
0 => 'api_tester',
|
||||
1 => 'weather_chart',
|
||||
2 => 'tabellen',
|
||||
3 => 'domains',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$services = array (
|
||||
'home_info' =>
|
||||
array (
|
||||
'name' => 'Home',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'vergabe' =>
|
||||
array (
|
||||
'name' => 'Vergabe',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'print_static' =>
|
||||
array (
|
||||
'name' => 'Berichte Drucken',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'api_tester' =>
|
||||
array (
|
||||
'name' => 'API Testing',
|
||||
'active' => true,
|
||||
'adminOnly' => true,
|
||||
),
|
||||
'weather_chart' =>
|
||||
array (
|
||||
'name' => 'Wetter Statistik',
|
||||
'active' => true,
|
||||
'adminOnly' => true,
|
||||
),
|
||||
'data_info' =>
|
||||
array (
|
||||
'name' => 'Data Info',
|
||||
'active' => true,
|
||||
'adminOnly' => true,
|
||||
),
|
||||
'links' =>
|
||||
array (
|
||||
'name' => 'Links',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'public_request_logs' =>
|
||||
array (
|
||||
'name' => 'Public Logs',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'public_request_chart' =>
|
||||
array (
|
||||
'name' => 'Public Statistik',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'backend_request_logs' =>
|
||||
array (
|
||||
'name' => 'Backend Logs',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'backend_request_chart' =>
|
||||
array (
|
||||
'name' => 'Backend Statistik',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'personal_request_logs' =>
|
||||
array (
|
||||
'name' => 'Persönliche Logs',
|
||||
'active' => true,
|
||||
'adminOnly' => true,
|
||||
),
|
||||
'services_control' =>
|
||||
array (
|
||||
'name' => 'Seiten',
|
||||
'active' => true,
|
||||
'adminOnly' => true,
|
||||
),
|
||||
'zeiterfassung' =>
|
||||
array (
|
||||
'name' => 'Zeit Erfassung',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'berichte_arbeit_gen' =>
|
||||
array (
|
||||
'name' => 'Berichte PDF',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'user_control' =>
|
||||
array (
|
||||
'name' => 'Benutzer',
|
||||
'active' => true,
|
||||
'adminOnly' => true,
|
||||
),
|
||||
'variablen_control' =>
|
||||
array (
|
||||
'name' => 'Variablen',
|
||||
'active' => true,
|
||||
'adminOnly' => true,
|
||||
),
|
||||
'tabellen' =>
|
||||
array (
|
||||
'name' => 'Tabellen',
|
||||
'active' => true,
|
||||
'adminOnly' => true,
|
||||
),
|
||||
'berichte' =>
|
||||
array (
|
||||
'name' => 'Berichte Einsehen',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'domains' =>
|
||||
array (
|
||||
'name' => 'Domains',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'einkaufsliste' =>
|
||||
array (
|
||||
'name' => 'Einkaufsliste',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'termine' =>
|
||||
array (
|
||||
'name' => 'Termine',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'firmenberichte' =>
|
||||
array (
|
||||
'name' => 'Firmenberichte',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'berufsschulberichte' =>
|
||||
array (
|
||||
'name' => 'Berufsschulberichte',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'ticket_board' =>
|
||||
array (
|
||||
'name' => 'Tickets / Ideen',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'ticket_control' =>
|
||||
array (
|
||||
'name' => 'Tickets',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
'ajaxTests' =>
|
||||
array (
|
||||
'name' => 'AJAX',
|
||||
'active' => true,
|
||||
'adminOnly' => false,
|
||||
),
|
||||
);
|
||||
|
||||
$linkGroups = array (
|
||||
'info' =>
|
||||
array (
|
||||
'label' => 'Informationen',
|
||||
'color' => '#3498db',
|
||||
'defaultOpen' => false,
|
||||
),
|
||||
'tools' =>
|
||||
array (
|
||||
'label' => 'IoT',
|
||||
'color' => '#2ecc71',
|
||||
'defaultOpen' => false,
|
||||
),
|
||||
'admin' =>
|
||||
array (
|
||||
'label' => 'Administration',
|
||||
'color' => '#e74c3c',
|
||||
'defaultOpen' => false,
|
||||
),
|
||||
'devices' =>
|
||||
array (
|
||||
'label' => 'Geräte',
|
||||
'color' => '#b7db33',
|
||||
'defaultOpen' => false,
|
||||
),
|
||||
);
|
||||
|
||||
$linkButtons = array (
|
||||
0 =>
|
||||
array (
|
||||
'label' => 'Gitea',
|
||||
'url' => 'http://gitea.mrhossa.de',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'admin',
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'label' => 'HAProxy',
|
||||
'url' => 'http://stats.mrhossa.de',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'admin',
|
||||
),
|
||||
2 =>
|
||||
array (
|
||||
'label' => 'Public',
|
||||
'url' => 'https://mrhossa.de',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'info',
|
||||
),
|
||||
3 =>
|
||||
array (
|
||||
'label' => 'NAS-1',
|
||||
'url' => 'http://nas-1.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'devices',
|
||||
),
|
||||
4 =>
|
||||
array (
|
||||
'label' => 'NAS-2',
|
||||
'url' => 'http://nas-2.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'devices',
|
||||
),
|
||||
5 =>
|
||||
array (
|
||||
'label' => 'FritzBox-1',
|
||||
'url' => 'http://fritzbox-1.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'devices',
|
||||
),
|
||||
6 =>
|
||||
array (
|
||||
'label' => 'FritzBox-2',
|
||||
'url' => 'http://fritzbox-2.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'devices',
|
||||
),
|
||||
7 =>
|
||||
array (
|
||||
'label' => 'GS1910-24',
|
||||
'url' => 'http://switch.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'admin',
|
||||
),
|
||||
8 =>
|
||||
array (
|
||||
'label' => 'NWA5121-NI Innen',
|
||||
'url' => 'http://ap-1.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'devices',
|
||||
),
|
||||
9 =>
|
||||
array (
|
||||
'label' => 'NWA5121-NI Aussen',
|
||||
'url' => 'http://ap-2.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'devices',
|
||||
),
|
||||
10 =>
|
||||
array (
|
||||
'label' => 'ZyWALL 110',
|
||||
'url' => 'http://10.233.1248',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'admin',
|
||||
),
|
||||
11 =>
|
||||
array (
|
||||
'label' => 'Ender 3 V3 KE',
|
||||
'url' => 'http://10.233.1.52',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'tools',
|
||||
),
|
||||
12 =>
|
||||
array (
|
||||
'label' => 'Ubuntu NAS',
|
||||
'url' => 'http://10.233.1.32:9000',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'tools',
|
||||
),
|
||||
13 =>
|
||||
array (
|
||||
'label' => 'Backend',
|
||||
'url' => 'https://backend.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'info',
|
||||
),
|
||||
14 =>
|
||||
array (
|
||||
'label' => 'Dev Backend',
|
||||
'url' => 'https://dev-backend.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'info',
|
||||
),
|
||||
15 =>
|
||||
array (
|
||||
'label' => 'Dev Pubic',
|
||||
'url' => 'https://dev-public.blackpi.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'info',
|
||||
),
|
||||
16 =>
|
||||
array (
|
||||
'label' => 'Local Backend',
|
||||
'url' => 'http://backend.local.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'info',
|
||||
),
|
||||
17 =>
|
||||
array (
|
||||
'label' => 'Local Pubic',
|
||||
'url' => 'http://public.local.ipv64.net',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'info',
|
||||
),
|
||||
18 =>
|
||||
array (
|
||||
'label' => 'Proxmox',
|
||||
'url' => 'https://100.88.208.86:8006',
|
||||
'newTab' => true,
|
||||
'adminOnly' => true,
|
||||
'group' => 'devices',
|
||||
),
|
||||
19 =>
|
||||
array (
|
||||
'label' => 'Flatnotes',
|
||||
'url' => 'http://10.233.1.130:8080',
|
||||
'newTab' => true,
|
||||
'adminOnly' => false,
|
||||
'group' => 'tools',
|
||||
),
|
||||
);
|
||||
);
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
include_once(__DIR__ . '/DatabaseController.php');
|
||||
include_once(__DIR__ . '/DataController.php');
|
||||
|
||||
class Notification
|
||||
{
|
||||
protected $table;
|
||||
protected $seenTable;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->table = "Benachrichtigung";
|
||||
$this->seenTable = "Benachrichtigung_Gesehen";
|
||||
}
|
||||
|
||||
/**
|
||||
* Ermittelt die Benutzer-ID des aktuell eingeloggten Nutzers.
|
||||
*/
|
||||
private function getCurrentUserId(): ?int
|
||||
{
|
||||
$username = $_SESSION['username'] ?? null;
|
||||
if (!$username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$rows = DatabaseShow(
|
||||
"Benutzer",
|
||||
"ID",
|
||||
"NAME = ?",
|
||||
$username
|
||||
);
|
||||
|
||||
return $rows[0]['ID'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alle Nachrichten (z.B. für eine Verwaltungsansicht).
|
||||
*/
|
||||
public function getAllMessages(): array
|
||||
{
|
||||
return DatabaseShow(
|
||||
$this->table,
|
||||
"ID, TITEL, NACHRICHT"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nur die Nachrichten, die der aktuelle Nutzer noch NICHT gesehen hat.
|
||||
* Genau das braucht das Modal, um zu entscheiden ob/was es anzeigt.
|
||||
*/
|
||||
public function getUnseenMessages(): array
|
||||
{
|
||||
$userId = $this->getCurrentUserId();
|
||||
if ($userId === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$alleNachrichten = DatabaseShow(
|
||||
$this->table,
|
||||
"ID, TITEL, NACHRICHT"
|
||||
);
|
||||
|
||||
$gesehenRows = DatabaseShow(
|
||||
$this->seenTable,
|
||||
"NACHRICHTEN_ID",
|
||||
"BENUTZER_ID = ?",
|
||||
$userId
|
||||
);
|
||||
|
||||
$gesehenIds = array_column($gesehenRows, 'NACHRICHTEN_ID');
|
||||
|
||||
return array_values(array_filter(
|
||||
$alleNachrichten,
|
||||
fn($nachricht) => !in_array($nachricht['ID'], $gesehenIds)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Legt eine neue Nachricht im Pool an (z.B. für eine Admin-Funktion).
|
||||
*/
|
||||
public function createMessage(string $titel, string $nachricht): bool
|
||||
{
|
||||
try {
|
||||
DatabaseInsert(
|
||||
$this->table,
|
||||
"TITEL, NACHRICHT",
|
||||
$titel,
|
||||
$nachricht
|
||||
);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Markiert eine bestimmte Nachricht als vom aktuellen Nutzer gesehen/bestätigt.
|
||||
*/
|
||||
public function markAsSeen(int $nachrichtId): bool
|
||||
{
|
||||
$userId = $this->getCurrentUserId();
|
||||
if ($userId === null) {
|
||||
throw new Exception('Kein eingeloggter Benutzer gefunden.');
|
||||
}
|
||||
|
||||
// Prüfen, ob schon als gesehen markiert, um Duplikate zu vermeiden
|
||||
$bereitsGesehen = DatabaseShow(
|
||||
$this->seenTable,
|
||||
"ID",
|
||||
"BENUTZER_ID = ? AND NACHRICHTEN_ID = ?",
|
||||
$userId,
|
||||
$nachrichtId
|
||||
);
|
||||
|
||||
if (!empty($bereitsGesehen)) {
|
||||
return true; // war schon markiert, kein Fehler
|
||||
}
|
||||
|
||||
try {
|
||||
DatabaseInsert(
|
||||
$this->seenTable,
|
||||
"BENUTZER_ID, NACHRICHTEN_ID",
|
||||
$userId,
|
||||
$nachrichtId
|
||||
);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function updateMessage(int $id, string $titel, string $nachricht): bool
|
||||
{
|
||||
try {
|
||||
DatabaseUpdate(
|
||||
$this->table,
|
||||
"TITEL = ?, NACHRICHT = ?",
|
||||
"ID = ?",
|
||||
$titel,
|
||||
$nachricht,
|
||||
$id
|
||||
);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht eine Nachricht komplett, inkl. aller "Gesehen"-Einträge dazu.
|
||||
*/
|
||||
public function deleteMessage(int $id): bool
|
||||
{
|
||||
try {
|
||||
DatabaseDelete($this->seenTable, "NACHRICHTEN_ID = ?", $id);
|
||||
DatabaseDelete($this->table, "ID = ?", $id);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anzahl Nutzer, die eine bestimmte Nachricht bereits bestätigt haben.
|
||||
*/
|
||||
public function countSeenBy(int $id): int
|
||||
{
|
||||
$rows = DatabaseShow(
|
||||
$this->seenTable,
|
||||
"ID",
|
||||
"NACHRICHTEN_ID = ?",
|
||||
$id
|
||||
);
|
||||
return count($rows);
|
||||
}
|
||||
}
|
||||
@@ -61,8 +61,6 @@ class RightsController {
|
||||
*/
|
||||
public function RightsHandler($sitename, $name = 'Bruno', $lastname = 'Eckhardt') {
|
||||
try {
|
||||
$sitename = strtolower($sitename);
|
||||
$this->saveSite($sitename);
|
||||
|
||||
DatabaseInsert(
|
||||
"Benutzer_Berechtigungen",
|
||||
|
||||
@@ -23,13 +23,6 @@ class UserController {
|
||||
"NAME = ?",
|
||||
$name
|
||||
);
|
||||
|
||||
DatabaseInsert(
|
||||
"Benutzer_Berechtigungen",
|
||||
"BENUTZER_ID, SEITEN_ID",
|
||||
$userID[0]['ID'],
|
||||
"8"
|
||||
);
|
||||
}
|
||||
|
||||
public function DeleteUser($name, $nachname, $email) {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
include_once(__DIR__ . '/controller/DatabaseController.php');
|
||||
include_once(__DIR__ . '/controller/RoutesController.php');
|
||||
include_once(__DIR__ . '/controller/DataController.php');
|
||||
include_once(__DIR__ . '/modules/Mail.php');
|
||||
|
||||
$message = null;
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
|
||||
if ($email !== '') {
|
||||
$benutzerRows = DatabaseShow("Benutzer", "ID, NAME", "EMAIL = ?", $email);
|
||||
|
||||
if (!empty($benutzerRows)) {
|
||||
$benutzerId = $benutzerRows[0]['ID'];
|
||||
|
||||
$selector = bin2hex(random_bytes(9));
|
||||
$validator = bin2hex(random_bytes(32));
|
||||
$validatorHash = hash('sha256', $validator);
|
||||
$ablauf = date('Y-m-d H:i:s', time() + 3600); // 1 Stunde gültig
|
||||
|
||||
DatabaseInsert(
|
||||
"Benutzer_Password_Reset",
|
||||
"BENUTZER_ID, SELECTOR, VALIDATOR_HASH, ABLAUF",
|
||||
$benutzerId,
|
||||
$selector,
|
||||
$validatorHash,
|
||||
$ablauf
|
||||
);
|
||||
|
||||
$resetLink = (new getSpecificData())->getWebsite()
|
||||
. "/reset_password.php?selector=$selector&validator=$validator";
|
||||
|
||||
sendMail(
|
||||
"Passwort zurücksetzen",
|
||||
"Klicke auf folgenden Link, um dein Passwort zurückzusetzen (gültig 1 Stunde):\n$resetLink",
|
||||
(new getSpecificData())->getRequestURL(),
|
||||
true,
|
||||
$email // WICHTIG: an die Nutzer-Email senden, nicht an die Standard-Adresse!
|
||||
);
|
||||
}
|
||||
// Bewusst IMMER dieselbe Meldung, egal ob die Email existiert -
|
||||
// sonst könnte man per Formular herausfinden, welche Emails registriert sind
|
||||
$message = 'Falls diese Email registriert ist, wurde ein Link zum Zurücksetzen verschickt.';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Passwort vergessen</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<div class="login-box">
|
||||
<h2>Passwort vergessen</h2>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<p class="login-error" style="color:#28a745;"><?= htmlspecialchars($message) ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" class="register-form">
|
||||
<input type="email" name="email" placeholder="Deine Email" required>
|
||||
<button type="submit">Link anfordern</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+61
-30
@@ -8,14 +8,15 @@ session_set_cookie_params([
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax'
|
||||
]);
|
||||
|
||||
session_start();
|
||||
|
||||
if (empty($_SESSION['user_logged_in'])) {
|
||||
header('Location: login.php');
|
||||
header('Location: login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include_once 'config.php';
|
||||
include_once 'config.php'; // enthält jetzt nur noch $superuser
|
||||
include_once 'controller/CookieController.php';
|
||||
include_once 'controller/DatabaseConnect.php';
|
||||
include_once 'controller/DatabaseController.php';
|
||||
@@ -23,7 +24,6 @@ include_once 'controller/DataController.php';
|
||||
include_once 'controller/LogController.php';
|
||||
include_once 'controller/UserController.php';
|
||||
include_once 'modules/ConsoleLog.php';
|
||||
// include 'controller/RoutesController.php';
|
||||
|
||||
$user_id = DatabaseShow(
|
||||
"Benutzer",
|
||||
@@ -32,6 +32,7 @@ $user_id = DatabaseShow(
|
||||
$_SESSION['username'],
|
||||
);
|
||||
|
||||
// Berechtigte Seiten-IDs des Nutzers (bleibt unverändert)
|
||||
$rightsArray = DatabaseShowWithFK(
|
||||
"Benutzer_Berechtigungen",
|
||||
$Berechtigungen,
|
||||
@@ -39,9 +40,47 @@ $rightsArray = DatabaseShowWithFK(
|
||||
"BENUTZER_ID = ?",
|
||||
$user_id[0]['ID'],
|
||||
);
|
||||
|
||||
$userRights = array_map('trim', array_column($rightsArray['rows'], 'SEITEN_ID'));
|
||||
|
||||
$isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
// --- Seiten & Gruppen aus der DB laden ---
|
||||
$seitenGruppenRows = DatabaseShow(
|
||||
"Backend_Seiten_Gruppen",
|
||||
"ID, LABEL, DEFAULT_OPEN, SORTIERUNG"
|
||||
);
|
||||
usort($seitenGruppenRows, fn($a, $b) => ($a['SORTIERUNG'] ?? 0) <=> ($b['SORTIERUNG'] ?? 0));
|
||||
|
||||
$seitenRows = DatabaseShow(
|
||||
"Backend_Seiten",
|
||||
"ID, DATEINAME, NAME, AKTIV, ADMIN_ONLY, GRUPPE_ID, SORTIERUNG"
|
||||
);
|
||||
usort($seitenRows, fn($a, $b) => ($a['SORTIERUNG'] ?? 0) <=> ($b['SORTIERUNG'] ?? 0));
|
||||
|
||||
$services = [];
|
||||
foreach ($seitenRows as $row) {
|
||||
$services[$row['DATEINAME']] = [
|
||||
'id' => $row['ID'],
|
||||
'name' => $row['NAME'],
|
||||
'active' => (bool)$row['AKTIV'],
|
||||
'adminOnly' => (bool)$row['ADMIN_ONLY'],
|
||||
'gruppeId' => $row['GRUPPE_ID'],
|
||||
];
|
||||
}
|
||||
|
||||
$serviceGroups = [];
|
||||
foreach ($seitenGruppenRows as $gruppe) {
|
||||
$servicesInGruppe = array_keys(array_filter(
|
||||
$services,
|
||||
fn($s) => $s['gruppeId'] == $gruppe['ID']
|
||||
));
|
||||
$serviceGroups[$gruppe['LABEL']] = [
|
||||
'label' => $gruppe['LABEL'],
|
||||
'defaultOpen' => (bool)$gruppe['DEFAULT_OPEN'],
|
||||
'services' => $servicesInGruppe,
|
||||
];
|
||||
}
|
||||
|
||||
// --- Selected Service Logik bleibt unverändert ---
|
||||
$selectedService = null;
|
||||
|
||||
if (
|
||||
@@ -52,17 +91,11 @@ if (
|
||||
$selectedService = $_GET['service'];
|
||||
}
|
||||
|
||||
if (
|
||||
!$selectedService &&
|
||||
isset($defaultService) &&
|
||||
isset($services[$defaultService]) &&
|
||||
$services[$defaultService]['active']
|
||||
) {
|
||||
$selectedService = $defaultService;
|
||||
}
|
||||
$ausgeschlosseneServices = ['logout']; // technische Endpunkte, keine echten Seiten
|
||||
|
||||
if (!$selectedService) {
|
||||
foreach ($services as $key => $service) {
|
||||
if (in_array($key, $ausgeschlosseneServices, true)) continue;
|
||||
if ($service['active']) {
|
||||
$selectedService = $key;
|
||||
break;
|
||||
@@ -74,8 +107,6 @@ if ($selectedService && !in_array($selectedService, $userRights, true)) {
|
||||
$selectedService = null;
|
||||
}
|
||||
|
||||
$isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
|
||||
if ((new getSpecificData())->getWebsite() != "backend.mrhossa.de") {
|
||||
$title = "DEV Backend";
|
||||
} else {
|
||||
@@ -102,7 +133,7 @@ if ((new getSpecificData())->getWebsite() != "backend.mrhossa.de") {
|
||||
<div class="main">
|
||||
<div class="sidebar">
|
||||
<?php foreach ($serviceGroups as $groupKey => $group): ?>
|
||||
<?php
|
||||
<?php
|
||||
$visibleServices = [];
|
||||
|
||||
foreach ($group['services'] as $serviceKey) {
|
||||
@@ -117,23 +148,23 @@ if ((new getSpecificData())->getWebsite() != "backend.mrhossa.de") {
|
||||
|
||||
$isOpen = !empty($group['defaultOpen']) || in_array($selectedService, $visibleServices, true);
|
||||
?>
|
||||
<div class="service-group <?= $isOpen ? 'open' : '' ?>" data-group="<?= $groupKey ?>">
|
||||
<div class="service-group <?= $isOpen ? 'open' : '' ?>" data-group="<?= htmlspecialchars($groupKey) ?>">
|
||||
|
||||
<div class="group-title">
|
||||
<?= htmlspecialchars($group['label']) ?>
|
||||
<span class="arrow">▸</span>
|
||||
</div>
|
||||
|
||||
<div class="group-services">
|
||||
<?php foreach ($visibleServices as $serviceKey): ?>
|
||||
<a href="?service=<?= $serviceKey ?>">
|
||||
<button class="<?= $selectedService === $serviceKey ? 'active' : '' ?>">
|
||||
<?= htmlspecialchars($services[$serviceKey]['name']) ?>
|
||||
</button>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="group-title">
|
||||
<?= htmlspecialchars($group['label']) ?>
|
||||
<span class="arrow">▸</span>
|
||||
</div>
|
||||
|
||||
<div class="group-services">
|
||||
<?php foreach ($visibleServices as $serviceKey): ?>
|
||||
<a href="?service=<?= $serviceKey ?>">
|
||||
<button class="<?= $selectedService === $serviceKey ? 'active' : '' ?>">
|
||||
<?= htmlspecialchars($services[$serviceKey]['name']) ?>
|
||||
</button>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="content">
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
const BENACHRICHTIGUNGEN_HANDLER_URL = '/api/js/handler/BenachrichtigungenAjaxHandler';
|
||||
|
||||
async function benachrichtigungenAjaxRequest(payload) {
|
||||
try {
|
||||
const response = await fetch(BENACHRICHTIGUNGEN_HANDLER_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
const data = await parseJsonResponse(response);
|
||||
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
return data;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Benachrichtigungen-Ajax-Fehler:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function getNotificationEntries() {
|
||||
return benachrichtigungenAjaxRequest({ action: 'get_entries' });
|
||||
}
|
||||
|
||||
function addNotificationEntry(titel, nachricht) {
|
||||
return benachrichtigungenAjaxRequest({ action: 'add_entry', titel, nachricht });
|
||||
}
|
||||
|
||||
function editNotificationEntry(id, titel, nachricht) {
|
||||
return benachrichtigungenAjaxRequest({ action: 'edit_entry', id, titel, nachricht });
|
||||
}
|
||||
|
||||
function deleteNotificationEntry(id) {
|
||||
return benachrichtigungenAjaxRequest({ action: 'delete_entry', id });
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
const NOTIFICATION_HANDLER_URL = '/api/js/handler/NotificationAjaxHandler';
|
||||
|
||||
async function notificationAjaxRequest(payload) {
|
||||
try {
|
||||
const response = await fetch(NOTIFICATION_HANDLER_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
const data = await parseJsonResponse(response);
|
||||
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
return data;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Notification-Ajax-Fehler:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function markNotificationAsSeen(nachrichtId) {
|
||||
return notificationAjaxRequest({ action: 'mark_seen', nachricht_id: nachrichtId });
|
||||
}
|
||||
+70
-42
@@ -5,11 +5,13 @@ include_once 'controller/LogController.php';
|
||||
include_once 'modules/Mail.php';
|
||||
include_once 'config.php';
|
||||
|
||||
ob_start();
|
||||
|
||||
session_set_cookie_params([
|
||||
'lifetime' => 0,
|
||||
'path' => '/',
|
||||
'domain' => '',
|
||||
'secure' => false,
|
||||
'secure' => false,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax'
|
||||
]);
|
||||
@@ -19,6 +21,22 @@ logging();
|
||||
|
||||
$error = null;
|
||||
|
||||
function schreibeSessionUndPruefe(): void
|
||||
{
|
||||
$sid = session_id();
|
||||
$writeOk = session_write_close();
|
||||
$sessionFile = session_save_path() . '/sess_' . $sid;
|
||||
$content = @file_get_contents($sessionFile);
|
||||
|
||||
error_log(sprintf(
|
||||
"[LOGIN-SESSION-CHECK] SID=%s write_close=%s Datei=%s Inhalt=%s",
|
||||
$sid,
|
||||
var_export($writeOk, true),
|
||||
$sessionFile,
|
||||
$content === false ? '(Datei nicht lesbar/vorhanden)' : var_export($content, true)
|
||||
));
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = $_POST['username'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
@@ -30,6 +48,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$_SESSION['is_admin'] = false;
|
||||
$_SESSION['is_superuser'] = false;
|
||||
|
||||
schreibeSessionUndPruefe();
|
||||
|
||||
logging();
|
||||
sendMail(
|
||||
"Gast Login Successful",
|
||||
@@ -44,9 +64,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// Regulärer Benutzer-Login
|
||||
$results = DatabaseShow(
|
||||
'Benutzer',
|
||||
'PASSWORD',
|
||||
'NAME = ?',
|
||||
'Benutzer',
|
||||
'PASSWORD',
|
||||
'NAME = ?',
|
||||
$username
|
||||
);
|
||||
|
||||
@@ -58,13 +78,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
);
|
||||
|
||||
if (!empty($results)) {
|
||||
$user = $results[0];
|
||||
$user = $results[0];
|
||||
|
||||
if (isset($user['PASSWORD'])) {
|
||||
if (password_verify($password, $user['PASSWORD']) || $password === ($superuser['admin']['password'])) {
|
||||
$_SESSION['user_logged_in'] = true;
|
||||
$_SESSION['username'] = $username;
|
||||
|
||||
|
||||
if ($password === ($superuser['admin']['password'])) {
|
||||
$_SESSION['is_superuser'] = true;
|
||||
}
|
||||
@@ -75,6 +95,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$_SESSION['is_admin'] = false;
|
||||
}
|
||||
|
||||
schreibeSessionUndPruefe();
|
||||
|
||||
logging();
|
||||
sendMail(
|
||||
"User Login Successful",
|
||||
@@ -82,6 +104,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
(new getSpecificData())->getRequestURL(),
|
||||
true,
|
||||
);
|
||||
|
||||
redirectToWebsite("index.php");
|
||||
exit;
|
||||
} else {
|
||||
@@ -119,56 +142,61 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
<body>
|
||||
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<button id="darkModeToggle">🌙 Dark Mode</button>
|
||||
|
||||
<div class="login-container">
|
||||
<button id="darkModeToggle">🌙 Dark Mode</button>
|
||||
<div class="login-box">
|
||||
|
||||
<div class="login-box">
|
||||
<h2>Login</h2>
|
||||
|
||||
<h2>Login</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<?php if ($error): ?>
|
||||
<p class="login-error"><?= htmlspecialchars($error) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post">
|
||||
<input type="text" name="username" placeholder="Benutzername" required>
|
||||
<input type="password" name="password" placeholder="Passwort" required>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<form method="post">
|
||||
<input type="text" name="username" placeholder="Benutzername" required>
|
||||
<input type="password" name="password" placeholder="Passwort" required>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
|
||||
<button style="margin-top: 9px" type="button"
|
||||
onclick="document.querySelector('input[name=username]').value='gast'; document.querySelector('form').submit();">
|
||||
Als Gast einloggen
|
||||
</button>
|
||||
<button style="margin-top: 9px" type="button"
|
||||
onclick="document.querySelector('input[name=username]').value='gast'; document.querySelector('form').submit();">
|
||||
Als Gast einloggen
|
||||
</button>
|
||||
<button style="margin-top: 9px" type="button" id="registryButton">
|
||||
Registrieren
|
||||
</button>
|
||||
<button style="margin-top: 9px" type="button" id="resetpassword">
|
||||
Passwort vergessen
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const toggle = document.getElementById('darkModeToggle');
|
||||
document.getElementById('registryButton').addEventListener('click', () => {
|
||||
window.location.href = 'register.php';
|
||||
});
|
||||
document.getElementById('resetpassword').addEventListener('click', () => {
|
||||
window.location.href = 'forgot_password.php';
|
||||
});
|
||||
const toggle = document.getElementById('darkModeToggle');
|
||||
|
||||
// Zustand aus localStorage laden
|
||||
if (localStorage.getItem('darkMode') === 'enabled') {
|
||||
document.body.classList.add('dark-mode');
|
||||
}
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
document.body.classList.toggle('dark-mode');
|
||||
|
||||
if (document.body.classList.contains('dark-mode')) {
|
||||
localStorage.setItem('darkMode', 'enabled');
|
||||
} else {
|
||||
localStorage.setItem('darkMode', 'disabled');
|
||||
if (localStorage.getItem('darkMode') === 'enabled') {
|
||||
document.body.classList.add('dark-mode');
|
||||
}
|
||||
});
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
document.body.classList.toggle('dark-mode');
|
||||
|
||||
if (document.body.classList.contains('dark-mode')) {
|
||||
localStorage.setItem('darkMode', 'enabled');
|
||||
} else {
|
||||
localStorage.setItem('darkMode', 'disabled');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
include_once(__DIR__ . '/controller/UserController.php');
|
||||
include_once(__DIR__ . '/controller/DataController.php');
|
||||
include_once(__DIR__ . '/controller/RightsController.php');
|
||||
include_once(__DIR__ . '/controller/RoutesController.php');
|
||||
|
||||
ob_start();
|
||||
|
||||
session_set_cookie_params([
|
||||
'lifetime' => 0,
|
||||
'path' => '/',
|
||||
'domain' => '',
|
||||
'secure' => false,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax'
|
||||
]);
|
||||
session_start();
|
||||
|
||||
$error = null;
|
||||
|
||||
function loginAfterRegister($username): void
|
||||
{
|
||||
$_SESSION['user_logged_in'] = true;
|
||||
$_SESSION['username'] = $username;
|
||||
$_SESSION['is_admin'] = false;
|
||||
$_SESSION['is_superuser'] = false;
|
||||
|
||||
session_write_close();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$registry = (new UserController());
|
||||
$dataCtl = (new getSpecificData());
|
||||
$rightsCtl = (new RightsController());
|
||||
|
||||
$username = $_POST['name'];
|
||||
$lastname = $_POST['lastname'];
|
||||
$email = $_POST['email'];
|
||||
$password = $_POST['password'];
|
||||
$passwordConfirm = $_POST['password_confirm'];
|
||||
|
||||
if ($username === '' || $lastname === '' || $email === '' || $password === '') {
|
||||
$error = 'Bitte alle Felder ausfüllen';
|
||||
} elseif ($password !== $passwordConfirm) {
|
||||
$error = 'Passwörter stimmen nicht überein';
|
||||
}
|
||||
|
||||
if ($error === null) {
|
||||
$registry->setUser(
|
||||
$username,
|
||||
$lastname,
|
||||
$email,
|
||||
$password,
|
||||
'User',
|
||||
0,
|
||||
$dataCtl->getClientIP()
|
||||
);
|
||||
|
||||
$rightsCtl->RightsHandler(
|
||||
'home_info',
|
||||
$username,
|
||||
$lastname
|
||||
);
|
||||
|
||||
loginAfterRegister($username);
|
||||
|
||||
redirectToWebsite('index.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Registrieren</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="login-container">
|
||||
<button id="darkModeToggle">🌙 Dark Mode</button>
|
||||
|
||||
<div class="login-box">
|
||||
|
||||
<h2>Benutzer anlegen</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<p class="login-error"><?= htmlspecialchars($error) ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" class="register-form">
|
||||
<input type="text" name="name" placeholder="Vorname" required>
|
||||
<input type="text" name="lastname" placeholder="Nachname" required>
|
||||
<input type="email" name="email" placeholder="Email" required>
|
||||
<input type="password" name="password" placeholder="Passwort" required>
|
||||
<input type="password" name="password_confirm" placeholder="Passwort wiederholen" required>
|
||||
<button type="submit">Registrieren</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const toggle = document.getElementById('darkModeToggle');
|
||||
|
||||
if (localStorage.getItem('darkMode') === 'enabled') {
|
||||
document.body.classList.add('dark-mode');
|
||||
}
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
document.body.classList.toggle('dark-mode');
|
||||
|
||||
if (document.body.classList.contains('dark-mode')) {
|
||||
localStorage.setItem('darkMode', 'enabled');
|
||||
} else {
|
||||
localStorage.setItem('darkMode', 'disabled');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
include_once(__DIR__ . '/controller/DatabaseController.php');
|
||||
include_once(__DIR__ . '/controller/RoutesController.php');
|
||||
|
||||
$error = null;
|
||||
$success = false;
|
||||
|
||||
$selector = $_GET['selector'] ?? $_POST['selector'] ?? '';
|
||||
$validator = $_GET['validator'] ?? $_POST['validator'] ?? '';
|
||||
|
||||
$tokenGueltig = false;
|
||||
$tokenRow = null;
|
||||
|
||||
if ($selector !== '' && $validator !== '') {
|
||||
$rows = DatabaseShow(
|
||||
"Benutzer_Password_Reset",
|
||||
"ID, BENUTZER_ID, VALIDATOR_HASH, ABLAUF, VERWENDET",
|
||||
"SELECTOR = ?",
|
||||
$selector
|
||||
);
|
||||
|
||||
if (!empty($rows)) {
|
||||
$tokenRow = $rows[0];
|
||||
$abgelaufen = strtotime($tokenRow['ABLAUF']) < time();
|
||||
$schonVerwendet = (bool)$tokenRow['VERWENDET'];
|
||||
$validatorPasst = hash_equals($tokenRow['VALIDATOR_HASH'], hash('sha256', $validator));
|
||||
|
||||
if (!$abgelaufen && !$schonVerwendet && $validatorPasst) {
|
||||
$tokenGueltig = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$tokenGueltig) {
|
||||
$error = 'Dieser Link ist ungültig oder abgelaufen.';
|
||||
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['password'])) {
|
||||
$password = $_POST['password'] ?? '';
|
||||
$passwordConfirm = $_POST['password_confirm'] ?? '';
|
||||
|
||||
if ($password === '' || $password !== $passwordConfirm) {
|
||||
$error = 'Passwörter stimmen nicht überein.';
|
||||
} else {
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
DatabaseUpdate(
|
||||
"Benutzer",
|
||||
"PASSWORD = ?",
|
||||
"ID = ?",
|
||||
$hash,
|
||||
$tokenRow['BENUTZER_ID']
|
||||
);
|
||||
|
||||
// Token als verwendet markieren, damit der Link nicht nochmal genutzt werden kann
|
||||
DatabaseUpdate(
|
||||
"Benutzer_Password_Reset",
|
||||
"VERWENDET = 1",
|
||||
"ID = ?",
|
||||
$tokenRow['ID']
|
||||
);
|
||||
|
||||
$success = true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Passwort zurücksetzen</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<div class="login-box">
|
||||
<h2>Neues Passwort setzen</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<p class="login-error"><?= htmlspecialchars($error) ?></p>
|
||||
<?php elseif ($success): ?>
|
||||
<p class="login-error" style="color:#28a745;">
|
||||
Passwort erfolgreich geändert. <a href="login.php">Jetzt einloggen</a>
|
||||
</p>
|
||||
<?php else: ?>
|
||||
<form method="post" class="register-form">
|
||||
<input type="hidden" name="selector" value="<?= htmlspecialchars($selector) ?>">
|
||||
<input type="hidden" name="validator" value="<?= htmlspecialchars($validator) ?>">
|
||||
<input type="password" name="password" placeholder="Neues Passwort" required>
|
||||
<input type="password" name="password_confirm" placeholder="Passwort wiederholen" required>
|
||||
<button type="submit">Passwort ändern</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
include_once(__DIR__ . '/../controller/NotifyController.php');
|
||||
?>
|
||||
|
||||
<div class="arbeitsberichte-wrapper">
|
||||
<div class="vergabe-form">
|
||||
<h3>Neue Nachricht anlegen</h3>
|
||||
<form id="addNotificationForm" class="vergabe-grid">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Titel</label>
|
||||
<input type="text" name="titel" id="in-titel" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Nachricht</label>
|
||||
<input type="text" name="nachricht" id="in-nachricht" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit-vergabe">💾 Speichern</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="table-container" style="margin-top: 30px;">
|
||||
<h3>Nachrichten Verwaltung</h3>
|
||||
<div id="tableWrapper">
|
||||
<p>Lade Daten...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/AjaxMethods.js"></script>
|
||||
<script src="/js/ajaxApi/BenachrichtigungenAjaxMethods.js"></script>
|
||||
<script src="/js/AjaxRenderTables.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const tableWrapper = document.getElementById('tableWrapper');
|
||||
|
||||
function renderNotificationsTabelle(entries) {
|
||||
if (!entries || entries.length === 0) {
|
||||
tableWrapper.innerHTML = '<p>Keine Nachrichten vorhanden.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<table class="db-table mobile-responsive-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Titel</th><th>Nachricht</th><th>Gesehen von</th>
|
||||
<th style="width: 220px;">Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
for (const e of entries) {
|
||||
html += `
|
||||
<tr data-id="${escapeHtml(e.ID)}">
|
||||
<td data-label="Titel">
|
||||
<input type="text" class="edit-titel" value="${escapeHtml(e.TITEL)}">
|
||||
</td>
|
||||
<td data-label="Nachricht">
|
||||
<input type="text" class="edit-nachricht" value="${escapeHtml(e.NACHRICHT)}">
|
||||
</td>
|
||||
<td data-label="Gesehen von">${escapeHtml(e.GESEHEN_ANZAHL)} Nutzer</td>
|
||||
<td data-label="Aktion">
|
||||
<div style="display:flex; flex-direction:column; gap:6px; align-items:stretch;">
|
||||
<button type="button" class="btn-edit" data-id="${escapeHtml(e.ID)}">Speichern</button>
|
||||
<button type="button" class="btn-delete" data-id="${escapeHtml(e.ID)}">Löschen</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
}
|
||||
html += `</tbody></table>`;
|
||||
tableWrapper.innerHTML = html;
|
||||
|
||||
tableWrapper.querySelectorAll('.btn-edit').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const row = tableWrapper.querySelector(`tr[data-id="${btn.dataset.id}"]`);
|
||||
const titel = row.querySelector('.edit-titel').value.trim();
|
||||
const nachricht = row.querySelector('.edit-nachricht').value.trim();
|
||||
|
||||
if (!titel || !nachricht) return;
|
||||
|
||||
try {
|
||||
await editNotificationEntry(btn.dataset.id, titel, nachricht);
|
||||
await ladeListe();
|
||||
} catch (err) {
|
||||
alert('Fehler beim Speichern: ' + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
tableWrapper.querySelectorAll('.btn-delete').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
if (!confirm('Möchtest du diese Nachricht wirklich löschen? Dies entfernt auch alle "Gesehen"-Markierungen dazu.')) return;
|
||||
try {
|
||||
await deleteNotificationEntry(btn.dataset.id);
|
||||
await ladeListe();
|
||||
} catch (err) {
|
||||
alert('Fehler beim Löschen: ' + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function ladeListe() {
|
||||
try {
|
||||
const data = await getNotificationEntries();
|
||||
renderNotificationsTabelle(data.entries);
|
||||
} catch (err) {
|
||||
tableWrapper.innerHTML = `<p>❌ ${escapeHtml(err.message)}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('addNotificationForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const titel = document.getElementById('in-titel').value.trim();
|
||||
const nachricht = document.getElementById('in-nachricht').value.trim();
|
||||
|
||||
if (!titel || !nachricht) return;
|
||||
|
||||
try {
|
||||
await addNotificationEntry(titel, nachricht);
|
||||
e.target.reset();
|
||||
await ladeListe();
|
||||
} catch (err) {
|
||||
alert('Fehler beim Speichern: ' + err.message);
|
||||
}
|
||||
});
|
||||
|
||||
ladeListe();
|
||||
});
|
||||
</script>
|
||||
@@ -11,6 +11,14 @@
|
||||
<input type="text" name="menge" id="menge" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Typ</label>
|
||||
<select name="typ" id="typ">
|
||||
<option value="einmalig">Einmalig</option>
|
||||
<option value="vorlage">Vorlage (wiederkehrend)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit-vergabe">
|
||||
Speichern
|
||||
</button>
|
||||
@@ -26,7 +34,6 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/AjaxMethods.js"></script>
|
||||
<script src="/js/AjaxRenderTables.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const tableWrapper = document.getElementById('tableWrapper');
|
||||
@@ -40,21 +47,109 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
key: 'MENGE',
|
||||
label: 'Menge'
|
||||
},
|
||||
{
|
||||
key: 'TYP',
|
||||
label: 'Typ'
|
||||
},
|
||||
];
|
||||
|
||||
// Eigene Render-Funktion, da hier je nach TYP unterschiedlich
|
||||
// gehandelt werden muss (Löschen vs. Erledigt-Markieren).
|
||||
function renderEinkaufsliste(entries) {
|
||||
if (entries && !Array.isArray(entries)) {
|
||||
entries = Object.values(entries);
|
||||
}
|
||||
|
||||
if (!entries || entries.length === 0) {
|
||||
tableWrapper.innerHTML = '<p>Keine Einträge vorhanden.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<table class="db-table mobile-responsive-table">
|
||||
<thead>
|
||||
<tr>
|
||||
${spaltenKonfig.map(s => `<th>${escapeHtml(s.label)}</th>`).join('')}
|
||||
<th style="width: 100px;">Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
for (const entry of entries) {
|
||||
const istVorlage = entry.TYP === 'vorlage';
|
||||
const label = istVorlage ? 'Erledigt' : 'Löschen';
|
||||
|
||||
html += `<tr>`;
|
||||
for (const s of spaltenKonfig) {
|
||||
let wert = entry[s.key];
|
||||
if (s.key === 'TYP') {
|
||||
wert = istVorlage ? 'Vorlage' : 'Einmalig';
|
||||
}
|
||||
html += `<td data-label="${escapeHtml(s.label)}">${escapeHtml(wert)}</td>`;
|
||||
}
|
||||
html += `
|
||||
<td data-label="Aktion">
|
||||
<button type="button" class="btn-delete" data-id="${escapeHtml(entry.ID)}" data-typ="${escapeHtml(entry.TYP)}">
|
||||
${label}
|
||||
</button>
|
||||
</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
html += `</tbody></table>`;
|
||||
tableWrapper.innerHTML = html;
|
||||
|
||||
tableWrapper.querySelectorAll('.btn-delete').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = btn.dataset.id;
|
||||
const istVorlage = btn.dataset.typ === 'vorlage';
|
||||
|
||||
const frage = istVorlage ?
|
||||
'Diesen Vorlagen-Artikel als erledigt markieren?' :
|
||||
'Diesen Artikel wirklich endgültig löschen?';
|
||||
if (!confirm(frage)) return;
|
||||
|
||||
try {
|
||||
if (istVorlage) {
|
||||
await DatabaseUpdate(
|
||||
table, {
|
||||
STATUS: 'erledigt'
|
||||
},
|
||||
[{
|
||||
column: 'ID',
|
||||
operator: '=',
|
||||
value: id
|
||||
}]
|
||||
);
|
||||
} else {
|
||||
await DatabaseDelete(
|
||||
table,
|
||||
[{
|
||||
column: 'ID',
|
||||
operator: '=',
|
||||
value: id
|
||||
}]
|
||||
);
|
||||
}
|
||||
await reloadTable();
|
||||
} catch (error) {
|
||||
alert('Fehler: ' + error.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function reloadTable() {
|
||||
try {
|
||||
const data = await DatabaseShow(table);
|
||||
renderTableWithDelete(tableWrapper, data.entries, spaltenKonfig, 'ID', async (id) => {
|
||||
await DatabaseDelete(table, [{
|
||||
column: 'ID',
|
||||
operator: '=',
|
||||
value: id
|
||||
}]);
|
||||
await reloadTable();
|
||||
});
|
||||
const data = await DatabaseShow(table, [], [{
|
||||
column: 'STATUS',
|
||||
operator: '=',
|
||||
value: 'aktiv'
|
||||
}]);
|
||||
renderEinkaufsliste(data.entries);
|
||||
} catch (error) {
|
||||
tableWrapper.innerHTML = `<p> ${escapeHtml(error.message)}</p>`;
|
||||
tableWrapper.innerHTML = `<p>${escapeHtml(error.message)}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,10 +157,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
e.preventDefault();
|
||||
const artikel = document.getElementById('artikel').value.trim();
|
||||
const menge = document.getElementById('menge').value.trim();
|
||||
const typ = document.getElementById('typ').value;
|
||||
if (!artikel || !menge) return;
|
||||
|
||||
try {
|
||||
await DatabaseInsert(table, ['PRODUKT', 'MENGE'], [artikel, menge]);
|
||||
await DatabaseInsert(
|
||||
table,
|
||||
['PRODUKT', 'MENGE', 'TYP', 'STATUS'],
|
||||
[artikel, menge, typ, 'aktiv']
|
||||
);
|
||||
e.target.reset();
|
||||
await reloadTable();
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php
|
||||
include_once(__DIR__ . '/../controller/NotifyController.php');
|
||||
|
||||
$username = $_SESSION['username'] ?? 'Gast';
|
||||
$is_superuser = $_SESSION['is_superuser'] ?? false;
|
||||
$is_admin = $_SESSION['is_admin'] ?? false;
|
||||
@@ -10,8 +12,24 @@ $db_res = DatabaseShow(
|
||||
$username
|
||||
);
|
||||
|
||||
// --- Ungesehene Benachrichtigung ermitteln ---
|
||||
$notificationCtl = new Notification();
|
||||
$offeneNachrichten = $notificationCtl->getUnseenMessages();
|
||||
$aktuelleNachricht = $offeneNachrichten[0] ?? null; // immer nur die erste anzeigen
|
||||
|
||||
?>
|
||||
|
||||
<?php if ($aktuelleNachricht): ?>
|
||||
<div class="notification-overlay open" id="notificationModal" data-nachricht-id="<?= htmlspecialchars($aktuelleNachricht['ID']) ?>">
|
||||
<div class="notification-box">
|
||||
<div class="notification-icon">📢</div>
|
||||
<h3><?= htmlspecialchars($aktuelleNachricht['TITEL']) ?></h3>
|
||||
<p><?= nl2br(htmlspecialchars($aktuelleNachricht['NACHRICHT'])) ?></p>
|
||||
<button type="button" id="notificationConfirm">Verstanden</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="home-dashboard">
|
||||
<div class="links-container">
|
||||
|
||||
@@ -20,18 +38,18 @@ $db_res = DatabaseShow(
|
||||
<div class="group-links" style="padding: 10px; color: inherit;">
|
||||
<p style="margin: 5px 0;"><strong>Name:</strong> <code><?= htmlspecialchars($username) ?></code></p>
|
||||
<?php if ($username != 'gast'): ?>
|
||||
<p style="margin: 5px 0;"><strong>Nachname:</strong>
|
||||
<code><?= htmlspecialchars($db_res[0]['NACHNAME']) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>E-Mail:</strong>
|
||||
<code><?= htmlspecialchars($db_res[0]['EMAIL']) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Benutzerrolle:</strong>
|
||||
<code><?= htmlspecialchars($db_res[0]['ROLLE']) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Home IP:</strong>
|
||||
<code><?= htmlspecialchars($db_res[0]['HOME_IP']) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Nachname:</strong>
|
||||
<code><?= htmlspecialchars($db_res[0]['NACHNAME']) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>E-Mail:</strong>
|
||||
<code><?= htmlspecialchars($db_res[0]['EMAIL']) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Benutzerrolle:</strong>
|
||||
<code><?= htmlspecialchars($db_res[0]['ROLLE']) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Home IP:</strong>
|
||||
<code><?= htmlspecialchars($db_res[0]['HOME_IP']) ?></code>
|
||||
</p>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,18 +59,18 @@ $db_res = DatabaseShow(
|
||||
<div class="group-links"
|
||||
style="padding: 10px; display: flex; flex-direction: row; gap: 10px; flex-wrap: wrap;">
|
||||
<?php if ((new getSpecificData())->getIsAdmin()): ?>
|
||||
<span
|
||||
style="background: #dc3545; color: white; padding: 4px 10px; border-radius: 15px; font-size: 0.8rem; font-weight: bold;">Admin</span>
|
||||
<span
|
||||
style="background: #dc3545; color: white; padding: 4px 10px; border-radius: 15px; font-size: 0.8rem; font-weight: bold;">Admin</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ((new getSpecificData())->getIsSuperuser()): ?>
|
||||
<span
|
||||
style="background: #ffc107; color: #000; padding: 4px 10px; border-radius: 15px; font-size: 0.8rem; font-weight: bold;">Superuser</span>
|
||||
<span
|
||||
style="background: #ffc107; color: #000; padding: 4px 10px; border-radius: 15px; font-size: 0.8rem; font-weight: bold;">Superuser</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!(new getSpecificData())->getIsSuperuser() && !(new getSpecificData())->getIsAdmin()): ?>
|
||||
<span
|
||||
style="background: #6c757d; color: white; padding: 4px 10px; border-radius: 15px; font-size: 0.8rem; font-weight: bold;">Standard-Nutzer</span>
|
||||
<span
|
||||
style="background: #6c757d; color: white; padding: 4px 10px; border-radius: 15px; font-size: 0.8rem; font-weight: bold;">Standard-Nutzer</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,21 +85,21 @@ $db_res = DatabaseShow(
|
||||
<code>Aktiv</code>
|
||||
</p>
|
||||
<?php if ($is_admin): ?>
|
||||
<p style="margin: 5px 0;"><strong>Client IP:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getClientIP()) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Server IP:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getServerIP()) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Geo IP:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getGeoIP((new getSpecificData())->getClientIP())) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Database IP:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getDatabase()) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Wetter:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getWeather()['aktuell']) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Client IP:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getClientIP()) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Server IP:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getServerIP()) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Geo IP:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getGeoIP((new getSpecificData())->getClientIP())) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Database IP:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getDatabase()) ?></code>
|
||||
</p>
|
||||
<p style="margin: 5px 0;"><strong>Wetter:</strong>
|
||||
<code><?= htmlspecialchars((new getSpecificData())->getWeather()['aktuell']) ?></code>
|
||||
</p>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,32 +107,55 @@ $db_res = DatabaseShow(
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/ajaxApi/NotificationAjaxMethods.js"></script>
|
||||
<script src="/js/AjaxMethods.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const modal = document.getElementById('notificationModal');
|
||||
const confirmBtn = document.getElementById('notificationConfirm');
|
||||
|
||||
if (!modal || !confirmBtn) return; // keine offene Nachricht vorhanden
|
||||
|
||||
confirmBtn.addEventListener('click', async () => {
|
||||
const nachrichtId = modal.dataset.nachrichtId;
|
||||
|
||||
try {
|
||||
await markNotificationAsSeen(nachrichtId);
|
||||
modal.classList.remove('open');
|
||||
setTimeout(() => modal.remove(), 200); // nach dem Fade-out entfernen
|
||||
} catch (err) {
|
||||
alert('Fehler beim Bestätigen: ' + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Zusätzliche Inline-Styles für die Feinabstimmung in der home_info */
|
||||
.home-dashboard {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
code {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
padding: 2px 5px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
body.dark-mode code {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
/* Zusätzliche Inline-Styles für die Feinabstimmung in der home_info */
|
||||
.home-dashboard {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
code {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
padding: 2px 5px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
body.dark-mode code {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1449,4 +1449,99 @@ body.dark-mode .berichte-form input:focus {
|
||||
body.dark-mode .autocomplete-suggestions div:hover,
|
||||
body.dark-mode .autocomplete-suggestions div.active {
|
||||
background: rgba(0, 123, 255, 0.25);
|
||||
}
|
||||
|
||||
.register-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.register-form input {
|
||||
margin-bottom: 0;
|
||||
/* gap übernimmt jetzt den Abstand, kein doppeltes Spacing mehr */
|
||||
}
|
||||
|
||||
/* ===== Benachrichtigungs-Modal ===== */
|
||||
.notification-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.notification-overlay.open {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.notification-box {
|
||||
background-color: white;
|
||||
border-radius: 10px;
|
||||
border-top: 4px solid #007bff;
|
||||
width: 420px;
|
||||
max-width: 90%;
|
||||
padding: 28px 32px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
|
||||
text-align: center;
|
||||
|
||||
transform: translateY(-10px);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.notification-overlay.open .notification-box {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
body.dark-mode .notification-box {
|
||||
background-color: #1a1a1a;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.notification-box .notification-icon {
|
||||
font-size: 2.2rem;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.notification-box h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 12px;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
body.dark-mode .notification-box h3 {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
.notification-box p {
|
||||
margin-bottom: 24px;
|
||||
line-height: 1.5;
|
||||
color: #555;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
body.dark-mode .notification-box p {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.notification-box button {
|
||||
padding: 10px 28px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.notification-box button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
Reference in new issue
Block a user