diff --git a/.gitignore b/.gitignore index 2629c29..7ae91e8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ private-files/rechnungen/* .php-ini .php-version www/displays/json/* +www/intern/scripts/kampfrichter/ajax/neu.php +www/intern/scripts/kampfrichter/ajax/neu_copy.php \ No newline at end of file diff --git a/scripts/csrf_functions.php b/scripts/csrf_functions.php deleted file mode 100644 index 7b39431..0000000 --- a/scripts/csrf_functions.php +++ /dev/null @@ -1,16 +0,0 @@ - false, - 'message' => 'security check failed: ERROR 01' - ]); - exit; -} - -if ($token !== 'QQa2UMbEYW8oOL7wz9DjtqECVCikSZsDuSdmzxiadEXFsKyujEUyQOW1AYMD2OqU8VXxClIRweRuWLzvBrZpPYL41e89Rs96tM7Lq1KpjA5E2mg2UfgvztheGRV'){ - http_response_code(403); - echo json_encode([ - 'success' => false, - 'message' => 'security check failed: ERROR 02' - ]); - exit; -} - require __DIR__ . '/../../composer/vendor/autoload.php'; $envFile = realpath(__DIR__ . '/../../config/.env.db-guest'); diff --git a/scripts/db/db-verbindung-script.php b/scripts/db/db-verbindung-script.php index 6e214e3..c97eb3e 100644 --- a/scripts/db/db-verbindung-script.php +++ b/scripts/db/db-verbindung-script.php @@ -2,7 +2,9 @@ use Dotenv\Dotenv; -if(session_status() !== PHP_SESSION_ACTIVE) session_start(); +require_once __DIR__ . '/../session_functions.php'; + +ini_wkvs_session(); if (!isset($type)){ return [ @@ -12,22 +14,13 @@ if (!isset($type)){ } if ($type === 'kr'){ - if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) { - http_response_code(403); - exit; - } + check_user_permission('kampfrichter'); } elseif ($type === 'tr'){ - if (empty($_SESSION['access_granted_trainer']) || $_SESSION['access_granted_trainer'] !== true || empty($_SESSION['passcodetrainer_id']) || $_SESSION['passcodetrainer_id'] < 1) { - http_response_code(403); - exit; - } + check_user_permission('trainer'); } elseif ($type === 'wkl') { - if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 1 ) { - http_response_code(403); - exit; - } + check_user_permission('wk_leitung'); } elseif ($type === 'otl') { - if (empty($_SESSION['set_new_password_id_user']) || empty($_SESSION['set_new_password_granted']) || $_SESSION['set_new_password_granted'] !== true || $_SESSION['set_new_password_id_user'] < 1 ) { + if (empty($_SESSION['access_granted_db_otl']) || $_SESSION['access_granted_db_otl'] !== true) { http_response_code(403); exit; } diff --git a/scripts/kampfrichter/check-user-freigaben.php b/scripts/kampfrichter/check-user-freigaben.php index 7cb7b59..ac2129d 100644 --- a/scripts/kampfrichter/check-user-freigaben.php +++ b/scripts/kampfrichter/check-user-freigaben.php @@ -1,12 +1,6 @@ 0) { diff --git a/scripts/kampfrichter/post-handler.php b/scripts/kampfrichter/post-handler.php index cb115ce..a217ea7 100644 --- a/scripts/kampfrichter/post-handler.php +++ b/scripts/kampfrichter/post-handler.php @@ -1,277 +1,11 @@ "`note $d`", $disciplines)); - - $columns_array = array_merge( - ['id', 'programm'], - array_map(fn($d) => "note $d", $disciplines) - ); - - - $all_rows = db_select($mysqli, $tableTurnerinnen, $columns_array, 'bezahlt = ? OR bezahltoverride = ?', ['2', '5']); - - - $success = 0; - // Step 1: Calculate gesamtpunktzahl and update per row - foreach ($all_rows as $row) { - $sum = 0; - foreach ($disciplines as $discipline) { - $value = $row["note $discipline"]; - if (is_numeric($value)) { - $sum += floatval($value); - } - } - db_update($mysqli, $tableTurnerinnen, ['gesamtpunktzahl' => $sum], ['id' => $row['id']]); - $success++; - } - - // Step 2: Re-fetch rows grouped by programm with updated gesamtpunktzahl - - $all_programms = db_get_col($mysqli, "SELECT DISTINCT programm FROM ".$tableTurnerinnen); - foreach ($all_programms as $programm) { - $group = db_select($mysqli, $tableTurnerinnen, ['id', 'gesamtpunktzahl', 'note sprung', 'note barren', 'note balken', 'note boden', 'geburtsdatum'], 'programm = ? AND (bezahlt = ? OR bezahltoverride = ?)', [$programm, '2', '5']); - - usort($group, function ($a, $b) { - $scoreA = floatval($a['gesamtpunktzahl']); - $scoreB = floatval($b['gesamtpunktzahl']); - - if ($scoreA !== $scoreB) return $scoreB <=> $scoreA; - - // Only for top 3 tie-breaking - $scoresA = [ - floatval($a['note sprung']), - floatval($a['note barren']), - floatval($a['note balken']), - floatval($a['note boden']), - ]; - $scoresB = [ - floatval($b['note sprung']), - floatval($b['note barren']), - floatval($b['note balken']), - floatval($b['note boden']), - ]; - - rsort($scoresA); - rsort($scoresB); - - $sumTop3A = $scoresA[0] + $scoresA[1] + $scoresA[2]; - $sumTop3B = $scoresB[0] + $scoresB[1] + $scoresB[2]; - if (abs($sumTop3A - $sumTop3B) > 0.001) return $sumTop3B <=> $sumTop3A; - - $sumTop2A = $scoresA[0] + $scoresA[1]; - $sumTop2B = $scoresB[0] + $scoresB[1]; - if (abs($sumTop2A - $sumTop2B) > 0.001) return $sumTop2B <=> $sumTop2A; - - if (abs($scoresA[0] - $scoresB[0]) > 0.001) return $scoresB[0] <=> $scoresA[0]; - - // Younger participant ranks higher in case of full tie - $dateA = strtotime($a['geburtsdatum']); - $dateB = strtotime($b['geburtsdatum']); - return $dateB <=> $dateA; // later birthdate = younger = better - }); - - // Step 2: Assign ranks - $ranked = []; - $current_rank = 1; - $i = 0; - - while ($i < count($group)) { - $current = $group[$i]; - $tie_group = [$current]; - $j = $i + 1; - - while ($j < count($group)) { - $next = $group[$j]; - - // Tie logic - if ($current_rank <= 3) { - // Top 3: full tie-breaking - $is_tie = - round(floatval($current['gesamtpunktzahl']), 3) === round(floatval($next['gesamtpunktzahl']), 3) && - round(floatval($current['note sprung']), 3) === round(floatval($next['note sprung']), 3) && - round(floatval($current['note barren']), 3) === round(floatval($next['note barren']), 3) && - round(floatval($current['note balken']), 3) === round(floatval($next['note balken']), 3) && - round(floatval($current['note boden']), 3) === round(floatval($next['note boden']), 3) && - $current['geburtsdatum'] === $next['geburtsdatum']; - } else { - // Ranks > 3: only check gesamtpunktzahl - $is_tie = round(floatval($current['gesamtpunktzahl']), 3) === round(floatval($next['gesamtpunktzahl']), 3); - } - - if ($is_tie) { - $tie_group[] = $next; - $j++; - } else { - break; - } - } - - // Assign the same rank for all ties in ranks > 3 - foreach ($tie_group as $entry) { - $ranked[] = [ - 'id' => $entry['id'], - 'rang' => $current_rank - ]; - } - - $i += count($tie_group); - $current_rank += count($tie_group); - } - - // Step 3: Write all ranks to DB - foreach ($ranked as $r) { - db_update($mysqli, $tableTurnerinnen, ['rang' => $r['rang']], ['id' => $r['id']]); - } - } - - - $_SESSION['form_message'] = - $success . ' Einträge wurden aktualisiert und neu gerankt.'; - header("Location: ". $_SERVER['REQUEST_URI']); - exit; -} -} - -if ($selecteduser === 'admin' && isset($_POST['reset_scores'])) { -if (!verify_csrf()) { - $form_message = 'Sicherheitsproblem bei der Neuberechnung.'; -} else { - $all_rows = db_select($mysqli, $tableTurnerinnen, 'id'); - $success = 0; - foreach ($all_rows as $row) { - db_update($mysqli, $tableTurnerinnen, ['gesamtpunktzahl' => 0, 'rang' => 0], ['id' => $row['id']]); - $success++; - } - - $_SESSION['form_message'] = '
' . $success . ' Einträge wurden zurückgesetzt.
'; - header("Location: ". $_SERVER['REQUEST_URI']); - exit; -} -} - - -// === EDIT MODE: Load existing data if edit_id is present in URL === -$edit_row = null; -if (isset($_GET['edit_id']) && is_numeric($_GET['edit_id']) && !isset($_POST['submit_turnerinnen_form'])) { - $edit_id = intval($_GET['edit_id']); - - $edit_row = db_select($mysqli, $tableTurnerinnen, '*', 'id = ?', [$edit_id]); - - foreach ($disciplines as $discipline) { - if ($selecteduser === ucfirst($discipline) || $selecteduser === 'admin') { - $_POST["d-note_{$discipline}"] = $edit_row["d-note {$discipline}"] ?? - ''; - $_POST["note_{$discipline}"] = $edit_row["note {$discipline}"] ?? ''; - } - } - if ($selecteduser === 'admin') { - $gesamt = 0; - foreach ($disciplines as $discipline) { - if (isset($edit_row[0]["note {$discipline}"]) && is_numeric($edit_row[0]["note {$discipline}"])) { - $gesamt += floatval($edit_row[0]["note {$discipline}"]); - } - } - $_POST["gesamtpunktzahl"] = $gesamt; - $rang = isset($_POST['rang']) ? intval($_POST['rang']) : 0; // Safely get and cast to int - $data_to_insert["rang"] = $rang; - $data_formats[] = '%d'; - } - - $_POST['edit_id'] = $edit_id; -} - -if (isset($_POST['submit_turnerinnen_form'])) { - // Check nonce - if (!verify_csrf()) { - $form_message = 'Sicherheitsproblem: Ungültige Formularübermittlung.'; - } else { - - - foreach ($disciplines as $discipline) { - if ($selecteduser === ucfirst($discipline) || $selecteduser === 'admin') { - ${"d_note_$discipline"} = floatval($_POST["d-note_{$discipline}"]); - ${"note_$discipline"} = floatval($_POST["note_{$discipline}"]); - - // Add to data array - $data_to_insert["d-note $discipline"] = ${"d_note_$discipline"}; - $data_to_insert["note $discipline"] = ${"note_$discipline"}; - - $data_formats[] = '%f'; // float format for d-note - $data_formats[] = '%f'; - // float format for note - } - } - - if ($selecteduser === 'admin') { - $gesamtpunktzahl = isset($_POST['gesamtpunktzahl']) ? - intval($_POST['gesamtpunktzahl']) : 0; // Safely get and cast to int - $data_to_insert["gesamtpunktzahl"] = $gesamtpunktzahl; - $data_formats[] = '%f'; - // CORRECTED LINE: Get 'rang' from $_POST - $rang = isset($_POST['rang']) ? - intval($_POST['rang']) : 0; // Safely get and cast to int - $data_to_insert["rang"] = $rang; - $data_formats[] = '%d'; - } - - - - - - - // Check if we are editing an existing entry - $is_editing = isset($_POST['edit_id']) && is_numeric($_POST['edit_id']) && $_POST['edit_id'] > 0; - if ($is_editing) { - $edit_id = intval($_POST['edit_id']); - $updated = db_update($mysqli, $tableTurnerinnen, $data_to_insert, ['id' => $edit_id]); - if ($updated === false) { - $form_message = 'Fehler beim Aktualisieren des Eintrags.'; - } else if ($updated === 0) { - $form_message = 'Keine Änderungen vorgenommen.'; - } else { - $_SESSION['form_message'] = 'Eintrag erfolgreich aktualisiert!'; - $_POST = []; - - $parsed = parse_url($_SERVER['REQUEST_URI']); - - if (!isset($parsed['query'])) { - return $url; - } - - parse_str($parsed['query'], $query); - - unset($query[$param]); // remove the parameter - - $base = $parsed['path'] ?? ''; - $new_query = http_build_query($query); - - $url = $new_query ? $base . '?' . $new_query : $base; - - header("Location: ". $url); - - exit; - } - } - } -} - if ((isset($_POST['prev_abt'])) && !empty($_POST['prev_abt_submit'])) { + verify_csrf(); $value = $aktabt; if ($value > 1){ $value -= 1; @@ -285,10 +19,11 @@ if ((isset($_POST['prev_abt'])) && !empty($_POST['prev_abt_submit'])) { $stmt->close(); } header("Location: /intern/kampfrichter"); -exit; + exit; } if ((isset($_POST['next_abt'])) && !empty($_POST['next_abt_submit'])) { + verify_csrf(); $value = $aktabt; $maxvalue = db_get_var($mysqli, "SELECT name FROM $tableAbt ORDER BY name DESC LIMIT 1"); @@ -322,6 +57,7 @@ if ($_SESSION['last_abt'] !== $aktabt){ } if ((isset($_POST['prev_subabt'])) && !empty($_POST['prev_subabt_submit'])) { + verify_csrf(); $value = $_SESSION['currentsubabt']; if ($value > 1){ $_SESSION['currentsubabt']--; @@ -333,6 +69,7 @@ if ((isset($_POST['prev_subabt'])) && !empty($_POST['prev_subabt_submit'])) { } if ((isset($_POST['next_subabt'])) && !empty($_POST['next_subabt_submit'])) { + verify_csrf(); $value = $_SESSION['currentsubabt']; if ($value < $maxsubabt){ $_SESSION['currentsubabt']++; @@ -343,7 +80,8 @@ if ((isset($_POST['next_subabt'])) && !empty($_POST['next_subabt_submit'])) { exit; } -if ( isset($_POST['togle_advanced_mode_admin']) && !empty($_POST['togle_advanced_mode_admin_submit']) ) { +if ( isset($_POST['togle_advanced_mode_admin']) && !empty($_POST['togle_advanced_mode_admin_submit']) && !empty($_POST['csrf_token'])) { + verify_csrf(); $current_value = $focus_view_admin; $new_value = !$current_value; @@ -351,31 +89,4 @@ if ( isset($_POST['togle_advanced_mode_admin']) && !empty($_POST['togle_advanced header("Location: /intern/kampfrichter"); exit; -} - -if ((isset($_POST['upload_remove_pdf_for_programm'])) && !empty($_POST['programm_remove_export'])) { - - $current_year = date('Y'); - $monat = date('n'); - if ($monat > 6) $current_year++; - - $programm = trim($_POST['programm_remove_export']); - - $dir = $_SERVER['DOCUMENT_ROOT'] . '/wp-content/ergebnisse'; - if (!file_exists($dir)) { - mkdir($dir, 0755, true); - } - $localPath = $_SERVER['DOCUMENT_ROOT'] . "/wp-content/ergebnisse/KTBB_Ergebnisse_" . $programm . "_" . $current_year . ".pdf"; - - // --- ADDED CODE START --- - // Check if the file already exists and delete it - if (file_exists($localPath)) { - unlink($localPath); - } - // --- ADDED CODE END --- - - $_SESSION['form_message'] = 'PDF wurde gelöscht'; - - - header("Location: ". $_SERVER['REQUEST_URI']); } \ No newline at end of file diff --git a/scripts/login/login.php b/scripts/login/login.php index eaec7b7..4762c34 100644 --- a/scripts/login/login.php +++ b/scripts/login/login.php @@ -1,8 +1,8 @@ time()) { $error = "Zu viele fehlgeschlagene Anmeldeversuche. Bitte warte $minutes Minute(n)."; } elseif (isset($_POST[$logintype.'_login_submit'])) { - $token = "QQa2UMbEYW8oOL7wz9DjtqECVCikSZsDuSdmzxiadEXFsKyujEUyQOW1AYMD2OqU8VXxClIRweRuWLzvBrZpPYL41e89Rs96tM7Lq1KpjA5E2mg2UfgvztheGRV"; - require __DIR__ .'/../db/db-verbindung-script-guest.php'; require __DIR__ . "/../db/db-tables.php"; @@ -35,8 +33,9 @@ if ($_SESSION['lockout_time_'. $logintype] > time()) { $password = trim($_POST['access_passcode']); // Prepare statement - $stmt = $guest->prepare("SELECT * FROM $tableInternUsers WHERE username = ? LIMIT 1"); - $stmt->bind_param("s", $username); + $stmt = $guest->prepare("SELECT * FROM $tableInternUsers WHERE username = ? AND login_active = ? LIMIT 1"); + $loginActive = 1; + $stmt->bind_param("ss", $username, $loginActive); $stmt->execute(); $result = $stmt->get_result(); $user = $result->fetch_assoc(); @@ -60,7 +59,7 @@ if ($_SESSION['lockout_time_'. $logintype] > time()) { if (password_verify($password, $user['password_hash']) && in_array($logintype, $freigabe_values)) { foreach ($freigabe_values as $freigabe) { $_SESSION['access_granted_'. $freigabe] = true; - $_SESSION['passcode'. $freigabe .'_id'] = $user['id']; + $_SESSION['user_id_'. $freigabe] = $user['id']; $_SESSION['lockout_time_'. $freigabe] = 0; $_SESSION['login_attempts_'. $freigabe] = 0; } diff --git a/scripts/session_functions.php b/scripts/session_functions.php new file mode 100644 index 0000000..0bfaa47 --- /dev/null +++ b/scripts/session_functions.php @@ -0,0 +1,104 @@ + 0, + 'path' => '/', + 'domain' => '', + 'secure' => true, + 'httponly' => true, + 'samesite' => 'Lax', + ]); + + + session_start(); + } + + if ($regenerate) { + session_regenerate_id(true); + } + if ($set_csrf && !isset($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(64)); + } +} + +function verify_csrf() { + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $token = $_POST['csrf_token'] ?? ''; + if (!hash_equals($_SESSION['csrf_token'], $token)) { + http_response_code(403); + die("Access Denied: Invalid CSRF Token."); + } + } else { + http_response_code(403); + die("Access Denied: Invalid Request Type."); + } +} + +$allowedUserTypes = ['trainer', 'kampfrichter', 'wk_leitung']; + +function check_user_permission(string $type, bool $return = false) { + global $allowedUserTypes; + + if (!in_array($type, $allowedUserTypes, true)) { + if ($return) { + return false; + } else { + http_response_code(403); + die("Invalid User Type Configuration"); + } + } + + $accessKey = "access_granted_{$type}"; + $idKey = "user_id_{$type}"; + + $hasAccess = ($_SESSION[$accessKey] ?? false) === true; + $hasValidId = isset($_SESSION[$idKey]) && intval($_SESSION[$idKey]) > 0; + + if (!$hasAccess || !$hasValidId) { + if ($return) { + return false; + } else { + http_response_code(403); + die("Access Denied"); + } + } + + if ($return) { + return true; + } +} + +function check_multiple_allowed_permissions(array $types) { + $authorized = false; + + foreach ($types as $type) { + if (check_user_permission($type, true)) { + $authorized = true; + break; + } + } + + if (!$authorized) { + http_response_code(403); + die("Access Denied"); + } +} \ No newline at end of file diff --git a/scripts/string-calculator/string-calculator-functions.php b/scripts/string-calculator/string-calculator-functions.php index 06a7044..1fefaf4 100644 --- a/scripts/string-calculator/string-calculator-functions.php +++ b/scripts/string-calculator/string-calculator-functions.php @@ -13,9 +13,14 @@ use ChrisKonnertz\StringCalc\StringCalc; class NotenRechner { + private $Rfunctions = ["MAXR", "MINR", "AVGR", "SUMR"]; + private $RfunctionsSan = []; + public function __construct( private StringCalc $rechner = new StringCalc() - ) {} + ) { + $this->RfunctionsSan = implode('|', array_map('preg_quote', $this->Rfunctions)); + } /* Es wird ein Array mit allen Notentypen pro Gerät, Jahr und Person erwartet, so dass noten_bezeichnung_id als Key verwendet werden kann: @@ -95,7 +100,7 @@ class NotenRechner { } } - private function insertValuesComplex(string $schemaRaw, array $valuesArray, int $currentId) + private function insertValuesComplex(string $schemaRaw, array $valuesArray, int $currentId, int $runNumber) { $schema = $this->santinzeString($schemaRaw); $idsNeededArray = $this->getBenoetigteIdsComplex($schemaRaw); @@ -104,7 +109,6 @@ class NotenRechner { foreach ($idsNeededArray as $sina) { $noteId = $sina['noteId']; $geraetIdSearch = ($sina['geraetId'] === 'A') ? $currentId : $sina['geraetId']; - $runNumber = $sina['run'] ?? 1; if (!isset($valuesArray[$geraetIdSearch][$noteId][$runNumber])) { return ['success' => false, 'value' => "Fehlende Daten für Gerät $geraetIdSearch, Note $noteId, Lauf $runNumber"]; @@ -112,15 +116,13 @@ class NotenRechner { } try { - $returnStr = preg_replace_callback('/\{(\d+)(?:\[(\w*)\])?(?:\[(\d+)\])?\}/', function($m) use ($valuesArray, $currentId) { + $returnStr = preg_replace_callback('/\{(\d+)(?:\[(\w*)\])?(?:\[(\d+)\])?\}/', function($m) use ($valuesArray, $currentId, $runNumber) { $noteId = $m[1]; // Get value inside brackets, default to 'S' if none exists $rawGeraet = $m[2] ?? 'S'; $geraetId = ($rawGeraet === 'S' || $rawGeraet === '') ? $currentId : $rawGeraet; - $runNumber = isset($m[3]) ? (int)$m[3] : 1; - // Return value from [Device][Note][Run] return $valuesArray[$geraetId][$noteId][$runNumber] ?? 0; @@ -160,16 +162,120 @@ class NotenRechner { return $this->calculate($rechnungArray['value']); } - public function berechneStringComplex(string $schemaRaw, array $valuesArray = [], int $geraetId = 0) { + public function berechneStringComplex(string $schemaRaw, array $valuesArray = [], int $geraetId = 0, int $run_number = 0) { if ($schemaRaw === '') { return ['success' => false, 'value' => 'Leeres Schema']; } if ($geraetId === 0) { return ['success' => false, 'value' => 'Keine Geraet Id angegeben.']; } + if ($run_number === 0) { return ['success' => false, 'value' => 'Keine Run_Number angegeben.']; } - $rechnungArray = $this->insertValuesComplex($schemaRaw, $valuesArray, $geraetId); + $rechnungArray = $this->insertValuesComplex($schemaRaw, $valuesArray, $geraetId, $run_number); if (!isset($rechnungArray['success']) || !isset($rechnungArray['value']) || !$rechnungArray['success']) { - return ['success' => false, 'value' => $rechnungArray['value'] ?? 'Fehler beim Einsetzen der Werte oder Werte fehlen']; + return ['success' => false, 'value' => $rechnungArray['value'] . " RECHNUNG: " . $schemaRaw ?? 'Fehler beim Einsetzen der Werte oder Werte fehlen']; } return $this->calculate($rechnungArray['value']); } + + public function berechneStringComplexRun(string $schemaRaw, array $valuesArray = [], int $geraetId = 0, int $programm = 0, array $arrayRuns = []) { + if ($schemaRaw === '') { return ['success' => false, 'value' => 'Leeres Schema']; } + if ($geraetId === 0) { return ['success' => false, 'value' => 'Keine Geraet Id angegeben.']; } + if ($programm === 0) { return ['success' => false, 'value' => 'Kein Programm angegeben.']; } + if ($arrayRuns === []) { return ['success' => false, 'value' => 'Leeres Array Runs Noten.']; } + + $rechnung = $this->insertRunValues($schemaRaw, $valuesArray, $geraetId, $programm, $arrayRuns); + + if (!isset($rechnung) || $rechnung === '') { + return ['success' => false, 'value' => 'Fehler beim Einsetzen der Werte oder Werte fehlen']; + } + + return $this->calculate($rechnung); + } + + private function insertRunValues($schema, $valuesArray, $currentId, $programm, $arrayRuns) { + $pattern = '/(?P' . $this->RfunctionsSan . ')\((?P(?:(?R)|[^()])*)\)/'; + + return preg_replace_callback($pattern, function($m) use ($valuesArray, $currentId, $programm, $arrayRuns) { + $name = $m['fn_name']; + $content = $m['content']; + + // Resolve inner nested functions first + $content = $this->insertRunValues($content, $valuesArray, $currentId, $programm, $arrayRuns); + + if (!in_array($name, $this->Rfunctions)) { + return $m[0]; + } + + $parts = []; + + $ids = $this->getBenoetigteIdsComplex($content); + + $runCount = 0; + + foreach ($ids as $sid) { + $geraetId = ($sid['geraetId'] === 'A') ? $currentId : $sid['geraetId']; + $runCountN = $arrayRuns[$sid['noteId']][$geraetId][$programm] ?? $arrayRuns["default"] ?? 1; + + //var_dump($arrayRuns[$sid['noteId']][$geraetId][$programm]); + + if ($runCount !== $runCountN && $runCount !== 0) { return; } + $runCount = $runCountN; + } + + $string = ""; + switch ($name) { + case "AVGR": + case "SUMR": + for ($r = 1; $r <= $runCount; $r++) { + + $res = $this->insertValuesComplex($content, $valuesArray, $currentId, $r); + + // FIXED: Only bail if success is false + if (!$res['success']) { + return "0"; // Or handle error as needed + } + $parts[] = "(" . $res['value'] . ")"; + } + + $innerMath = implode(" + ", $parts); + $string = ($name === "AVGR") ? "(($innerMath) / $runCount)" : "($innerMath)"; + + //var_dump($string); + break; + + case "MAXR": + case "MINR": + $arrayRunValues = []; + for ($r = 1; $r <= $runCount; $r++) { + $res = $this->berechneStringComplex($content, $valuesArray, $currentId, $r); + + // FIXED: Access the ['value'] key of the returned array + if ($res['success']) { + $arrayRunValues[] = floatval($res['value']); + } else { + $arrayRunValues[] = 0; + } + } + // Safety check for empty arrays to prevent max() errors + if (empty($arrayRunValues)) return "0"; + + $string = ($name === "MAXR") ? max($arrayRunValues) : min($arrayRunValues); + break; + } + + return (string)$string; + }, $schema); + } + + public function checkRunFunctions(string $schemaRaw) { + + if ($schemaRaw === '') { + return ['success' => false, 'value' => 'Leeres Schema']; + } + + $schema = $this->santinzeString($schemaRaw); + + $pattern = '/(?P' . $this->RfunctionsSan . ')\((?:(?R)|[^()])*+\)/'; + + return (bool) preg_match($pattern, $schema); + } } \ No newline at end of file diff --git a/scripts/trainer/post-handler.php b/scripts/trainer/post-handler.php index bf498f0..9948744 100644 --- a/scripts/trainer/post-handler.php +++ b/scripts/trainer/post-handler.php @@ -1,16 +1,12 @@ prepare("DELETE FROM $tableTurnerinnen where id = ?"); @@ -113,6 +110,7 @@ if (isset($_POST['delete_id']) && verify_csrf()) { } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['xlsx_file'])) { + verify_csrf(); if ($_FILES['xlsx_file']['error'] === UPLOAD_ERR_OK) { @@ -240,54 +238,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['xlsx_file'])) { } - -if (!empty($_FILES['music_file']['name']) && isset($_POST['music_id'])) { - echo 'ja'; - $edit_id = (int) $_POST['music_id']; - $uploadedFile = $_FILES['music_file']; - - // Validate actual MIME type - $finfo = finfo_open(FILEINFO_MIME_TYPE); - $mimeType = finfo_file($finfo, $uploadedFile['tmp_name']); - finfo_close($finfo); - - $allowedTypes = ['audio/mpeg', 'audio/wav', 'audio/ogg']; - if (!in_array($mimeType, $allowedTypes, true)) { - die('Invalid file type.'); - } - - // Fetch and remove old file - $stmt = $mysqli->prepare("SELECT bodenmusik FROM $tableTurnerinnen WHERE id = ?"); - $stmt->bind_param("i", $edit_id); - $stmt->execute(); - $stmt->bind_result($oldurl); - $stmt->fetch(); - $stmt->close(); - - if (!empty($oldurl) && is_file($oldurl)) unlink($oldurl); - - // Ensure upload directory exists - $uploadDir = $baseDir . '/wk-musik-boden/'; - if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true); - - // Clean file name - $cleanName = preg_replace("/[^a-zA-Z0-9-_\.]/", "_", $uploadedFile['name']); - $filename = uniqid('music_', true) . '_' . $cleanName; - $targetPath = $uploadDir . $filename; - - if (move_uploaded_file($uploadedFile['tmp_name'], $targetPath)) { - $stmt = $mysqli->prepare("UPDATE $tableTurnerinnen SET bodenmusik = ? WHERE id = ?"); - $stmt->bind_param("si", $targetPath, $edit_id); - if (!$stmt->execute()) echo 'DB error: ' . $stmt->error; - $stmt->close(); - } else { - die('Failed to move uploaded file.'); - } - - header('Location: ' . $_SERVER['REQUEST_URI']); - exit; -} - $edit_row = null; if ($access_granted_trainer && isset($_GET['edit_id']) && is_numeric($_GET['edit_id']) && !isset($_POST['submit_turnerinnen_form'])) { $edit_id = intval($_GET['edit_id']); @@ -319,121 +269,117 @@ if ($access_granted_trainer && isset($_GET['edit_id']) && is_numeric($_GET['edit // === INSERT/UPDATE Handler === if ( $access_granted_trainer && isset($_POST['submit_turnerinnen_form']) ) { // Check nonce - if ( !verify_csrf() ) { - $_SESSION['form_message'] = 'Sicherheitsproblem: Ungültige Formularübermittlung.'; + verify_csrf(); + $name = htmlspecialchars( $_POST['nachname'] ); + $vorname = htmlspecialchars( $_POST['vorname'] ); + $geburtsdatum = trim($_POST['geburtsdatum'] ); + $programm = htmlspecialchars( $_POST['programm'] ); + if ($selectedverein !== 'admin'){ + $verein = $selectedverein; + } else {$verein = htmlspecialchars( $_POST['verein'] ); $bezahlt = htmlspecialchars( $_POST['bezahlt'] ); } + if ( empty($name) || empty($vorname) || empty($geburtsdatum) || empty($programm)) { + $_SESSION['form_message'] = 'Bitte füllen Sie alle erforderlichen Felder aus.'; $_SESSION['form_message_type'] = 0; } else { - $name = htmlspecialchars( $_POST['nachname'] ); - $vorname = htmlspecialchars( $_POST['vorname'] ); - $geburtsdatum = trim($_POST['geburtsdatum'] ); - $programm = htmlspecialchars( $_POST['programm'] ); - if ($selectedverein !== 'admin'){ - $verein = $selectedverein; - } else {$verein = htmlspecialchars( $_POST['verein'] ); $bezahlt = htmlspecialchars( $_POST['bezahlt'] ); } - if ( empty($name) || empty($vorname) || empty($geburtsdatum) || empty($programm)) { - $_SESSION['form_message'] = 'Bitte füllen Sie alle erforderlichen Felder aus.'; - $_SESSION['form_message_type'] = 0; + + $data_to_insert = []; + + $data_to_insert = array( + 'name' => $name, + 'vorname' => $vorname, + 'geburtsdatum' => $geburtsdatum, + 'programm' => $programm, + 'verein' => $verein, + ); + + + $data_formats = array('%s', '%s', '%s', '%s', '%s'); + + if ($selectedverein === 'admin') { + $data_to_insert['bezahltoverride'] = $bezahlt; + $data_formats[] = '%d'; + } + + print_r($data_to_insert); + + + // Check if we are editing an existing entry + $is_editing = isset($_POST['edit_id']) && is_numeric($_POST['edit_id']) && $_POST['edit_id'] > 0; + + if ($is_editing) { + $edit_id = intval($_POST['edit_id']); + + $entries = db_select($mysqli, $tableTurnerinnen, '*', 'id = ?', [$edit_id], 'rang ASC'); + + $entry = $entries[0]; // since you're fetching by ID, this should return exactly one row + + $columns = array_keys($data_to_insert); + + $set = implode( + ', ', + array_map(fn($col) => "$col = ?", $columns) + ); + + $sql = "UPDATE $tableTurnerinnen SET $set WHERE id = ?"; + + var_dump($sql); + $stmt = $mysqli->prepare($sql); + + $types = str_repeat('s', count($data_to_insert)) . 'i'; + $values = array_values($data_to_insert); + $values[] = $edit_id; + + $stmt->bind_param($types, ...$values); + + $updated = $stmt->execute(); + + $stmt->close(); + + if ($updated === false) { + error_log('DB Update Error: ' . $wpdb->last_error); + $_SESSION['form_message'] = 'Fehler beim Aktualisieren des Eintrags.'; + $_SESSION['form_message_type'] = 0; + } else if ($updated === 0) { + $_SESSION['form_message'] = 'Keine Änderungen vorgenommen.'; + $_SESSION['form_message_type'] = 0; + } else { + $_SESSION['form_message'] = 'Eintrag erfolgreich aktualisiert!'; + $_SESSION['form_message_type'] = 1; + $_POST = []; + header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?')); + exit; + } } else { - $data_to_insert = []; - - $data_to_insert = array( - 'name' => $name, - 'vorname' => $vorname, - 'geburtsdatum' => $geburtsdatum, - 'programm' => $programm, - 'verein' => $verein, + $columns = array_keys($data_to_insert); + + $set = implode( + ', ', + array_map(fn($col) => "$col = ?", $columns) ); - - $data_formats = array('%s', '%s', '%s', '%s', '%s'); + $sql = "INSERT INTO $tableTurnerinnen SET $set"; - if ($selectedverein === 'admin') { - $data_to_insert['bezahltoverride'] = $bezahlt; - $data_formats[] = '%d'; - } + $stmt = $mysqli->prepare($sql); - print_r($data_to_insert); + $types = str_repeat('s', count($data_to_insert)); + $values = array_values($data_to_insert); + + $stmt->bind_param($types, ...$values); + + $inserted = $stmt->execute(); + + $stmt->close(); - // Check if we are editing an existing entry - $is_editing = isset($_POST['edit_id']) && is_numeric($_POST['edit_id']) && $_POST['edit_id'] > 0; - - if ($is_editing) { - $edit_id = intval($_POST['edit_id']); - - $entries = db_select($mysqli, $tableTurnerinnen, '*', 'id = ?', [$edit_id], 'rang ASC'); - - $entry = $entries[0]; // since you're fetching by ID, this should return exactly one row - - $columns = array_keys($data_to_insert); - - $set = implode( - ', ', - array_map(fn($col) => "$col = ?", $columns) - ); - - $sql = "UPDATE $tableTurnerinnen SET $set WHERE id = ?"; - - var_dump($sql); - $stmt = $mysqli->prepare($sql); - - $types = str_repeat('s', count($data_to_insert)) . 'i'; - $values = array_values($data_to_insert); - $values[] = $edit_id; - - $stmt->bind_param($types, ...$values); - - $updated = $stmt->execute(); - - $stmt->close(); - - if ($updated === false) { - error_log('DB Update Error: ' . $wpdb->last_error); - $_SESSION['form_message'] = 'Fehler beim Aktualisieren des Eintrags.'; - $_SESSION['form_message_type'] = 0; - } else if ($updated === 0) { - $_SESSION['form_message'] = 'Keine Änderungen vorgenommen.'; - $_SESSION['form_message_type'] = 0; - } else { - $_SESSION['form_message'] = 'Eintrag erfolgreich aktualisiert!'; - $_SESSION['form_message_type'] = 1; - $_POST = []; - header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?')); - exit; - } + if ( $inserted ) { + $_SESSION['form_message'] = 'Daten erfolgreich gespeichert!'; + $_SESSION['form_message_type'] = 1; + header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?')); + exit; } else { - - $columns = array_keys($data_to_insert); - - $set = implode( - ', ', - array_map(fn($col) => "$col = ?", $columns) - ); - - $sql = "INSERT INTO $tableTurnerinnen SET $set"; - - $stmt = $mysqli->prepare($sql); - - $types = str_repeat('s', count($data_to_insert)); - $values = array_values($data_to_insert); - - $stmt->bind_param($types, ...$values); - - $inserted = $stmt->execute(); - - $stmt->close(); - - - if ( $inserted ) { - $_SESSION['form_message'] = 'Daten erfolgreich gespeichert!'; - $_SESSION['form_message_type'] = 1; - header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?')); - exit; - } else { - $_SESSION['form_message'] = 'Fehler beim Speichern der Daten. Bitte versuchen Sie es später erneut.'; - $_SESSION['form_message_type'] = 0; - } + $_SESSION['form_message'] = 'Fehler beim Speichern der Daten. Bitte versuchen Sie es später erneut.'; + $_SESSION['form_message_type'] = 0; } } } diff --git a/www/displays/display.php b/www/displays/display.php index 3d52ebf..f27d68d 100644 --- a/www/displays/display.php +++ b/www/displays/display.php @@ -7,8 +7,6 @@ $lastSegment = strtolower($_GET['geraet']) ?? ''; $baseDir = $_SERVER['DOCUMENT_ROOT']; -$token = "QQa2UMbEYW8oOL7wz9DjtqECVCikSZsDuSdmzxiadEXFsKyujEUyQOW1AYMD2OqU8VXxClIRweRuWLzvBrZpPYL41e89Rs96tM7Lq1KpjA5E2mg2UfgvztheGRV"; - require_once $baseDir . '/../scripts/db/db-verbindung-script-guest.php'; require_once $baseDir . '/../scripts/db/db-functions.php'; require_once $baseDir . '/../scripts/db/db-tables.php'; diff --git a/www/intern/css/einstellungen.css b/www/intern/css/einstellungen.css index ad9534f..5ff1bb5 100644 --- a/www/intern/css/einstellungen.css +++ b/www/intern/css/einstellungen.css @@ -1,16 +1,18 @@ :root { --paddingSite: 40px; - --card-radius: 20px; + --card-radius: 24px; --card-bg: #ffffff; - --bg: #FDFDFD; - --card-shadow: 0 10px 30px rgba(15, 23, 42, 0.08); - --accent: #2d73ac; + --bg: #F4F3EF; + --card-shadow: 0 12px 40px rgba(0, 0, 0, 0.04); + --accent: #FF5A5F; + /* Soft energetic pink/red from Dribbble */ + --accent-secondary: #FF8A65; --bg-top: rgb(54, 137, 13); --bg-top-raw: 54 137 13; --accent-soft: #f0f5ff; - --border-subtle: #d4d7e1; - --text-main: #191919; - --text-muted: #5e5e5e; + --border-subtle: #eaeaea; + --text-main: #1b1b1b; + --text-muted: #8A8A8A; --disabled-bg: #f3f4f6; --disabled-border: #cbd5f5; } @@ -21,15 +23,6 @@ *::after, *::before { box-sizing: border-box; - -webkit-tap-highlight-color: transparent; - font-family: "Google Sans Flex", sans-serif; - font-optical-sizing: auto; - font-style: normal; - font-variation-settings: - "slnt" 0, - "wdth" 100, - "GRAD" 0, - "ROND" 0; } html, @@ -43,6 +36,7 @@ body { margin: 0; width: 100vw; background: var(--bg); + overflow-x: hidden; } ::selection { @@ -80,7 +74,7 @@ input { background: none; } -@media (min-width: 1000px) { +@media (min-width: 1081px) { .bgSection.open { width: calc(100vw - 380px); /* - 2 * var(--paddingSite) */ @@ -91,20 +85,44 @@ input { .headerDivTrainer { padding: var(--paddingSite); - background-color: var(--bg-top); - margin-bottom: var(--paddingSite); + padding-bottom: 10px; + background: transparent; + margin-bottom: 20px; position: relative; z-index: 3; } +.dashboardGrid { + padding: 0 var(--paddingSite) var(--paddingSite); + display: grid; + grid-template-columns: 1fr; + gap: 30px; + align-items: start; + width: 100%; +} +.twoColumDiv { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 30px; + align-items: start; + width: 100%; +} + +@media (max-width: 1080px) { + .twoColumDiv { + grid-template-columns: 1fr; + } +} /* headings */ .containerHeading { margin-top: 0; - font-weight: 400; - margin-bottom: 20px; + font-weight: 600; + font-size: 20px; + margin-bottom: 24px; + color: var(--text-main); } .divLiveSyncronisation { @@ -156,13 +174,15 @@ input { } .headingPanelDiv>* { - color: var(--bg); + color: var(--text-main); } .headingPanel { margin-top: 0; margin-bottom: 10px; - font-weight: 200; + font-size: 38px; + font-weight: 700; + letter-spacing: -0.02em; } .headingPanelUser { @@ -227,18 +247,21 @@ table { } .wkvsTabelle th { - color: #424242; - border-bottom: solid 1px #0000007d; + color: var(--text-muted); + border-bottom: solid 1px var(--border-subtle); font-weight: 600; - padding: 14px 15px; - font-size: 16px; + padding: 16px 15px; + font-size: 14px; + text-transform: uppercase; + letter-spacing: 0.05em; + background: transparent; } .wkvsTabelle td { - background-color: #ffffff; - color: #191919; - font-weight: 400; - padding: 14px 15px; + background-color: transparent; + color: var(--text-main); + font-weight: 500; + padding: 16px 15px; background: none; text-align: center; } @@ -248,7 +271,11 @@ table { } .wkvsTabelle td:not(.totalTd, .totalValue) { - border-bottom: solid 1px #6262624d; + border-bottom: solid 1px var(--border-subtle); +} + +.wkvsTabelle tr:last-child td { + border-bottom: none; } /*.wkvsTabelle .totalValue { @@ -290,14 +317,20 @@ table { /* Panel with inputs (new style, light) */ .containerDiv { + background: var(--card-bg); + border-radius: var(--card-radius); + padding: 32px; + box-shadow: var(--card-shadow); color: var(--text-main); display: flex; flex-direction: column; + min-width: 0; + /* Critical for grid item content overflow */ } .settingsGrid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); + grid-template-columns: 1fr; gap: 20px; margin-bottom: 30px; } @@ -309,38 +342,100 @@ table { } .settingsRow span { - font-size: 13px; + font-size: 16px; color: var(--text-muted); - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; + font-weight: 500; + margin-bottom: 2px; } -.settingsRow input { - padding: 10px 14px; - border: 1px solid var(--border-subtle); - border-radius: 10px; +.settingsRow input, +.settingsRow select { + padding: 14px 18px; + border: none; + background: #F8F9FA; + border-radius: 12px; font-size: 15px; transition: all 0.2s ease; - background: #ffffff; + color: var(--text-main); width: 100%; } -.settingsRow input:hover { - border-color: #adb5bd; +.settingsRow input:hover, +.settingsRow select:hover { + background: #F1F3F5; } -.settingsRow input:focus { - border-color: var(--bg-top); +.settingsRow input:focus, +.settingsRow select:focus { + background: #FFFFFF; box-shadow: 0 0 0 4px rgba(var(--bg-top-raw), 0.1); outline: none; } .settingsRow input[type="color"] { - height: 42px; - padding: 4px; + height: 48px; + padding: 0px; cursor: pointer; - border-radius: 10px; + border-radius: 12px; + border: 1px solid #cacaca; + -webkit-appearance: none; + appearance: none; + /* Removes default Chrome/Safari styles */ + cursor: pointer; + background: none; +} + + +/* Container for the color swatch (Chrome/Safari) */ +input[type="color"]::-webkit-color-swatch-wrapper { + padding: 0; +} + +/* The actual color area (Chrome/Safari) */ +input[type="color"]::-webkit-color-swatch { + border: none; + /* Makes the picker a circle */ +} + +/* The actual color area (Firefox) */ +input[type="color"]::-moz-color-swatch { + border: none; +} + +.containerImages { + display: flex; + flex-direction: column; + gap: 15px; +} + +.containerImages span { + position: absolute; + bottom: 4px; + padding: 12px; + width: 100%; + text-align: center; + background-color: #00000063; + backdrop-filter: blur(2px); + border-radius: 0 0 7px 7px; + border-top: 1px solid #fff; + color: #fff; +} + +.containerImages>div { + display: flex; + align-items: center; + justify-content: space-between; + position: relative; +} + +.containerImages>div:last-child { + border-bottom: none; +} + +.containerImages img { + width: 100%; + border-radius: 8px; + object-fit: cover; } .editContainerDivInner>form { @@ -593,16 +688,19 @@ input[type="number"]::-webkit-outer-spin-button { display: flex; align-items: center; justify-content: center; - width: 28px; - height: 28px; + width: 44px; + height: 44px; + background: #FFFFFF; + border-radius: 50%; cursor: pointer; z-index: 99; - color: var(--bg); + color: var(--text-main); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06); } .trainerBurgerMenuDiv svg { - width: 100%; - height: 100%; + width: 24px; + height: 24px; stroke: currentColor; transition: transform 0.3s ease; } @@ -975,8 +1073,8 @@ tr.rowStartgebuer::after { } .containerImages { - display: flex; - flex-wrap: wrap; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); align-items: flex-start; gap: 24px; } @@ -984,11 +1082,9 @@ tr.rowStartgebuer::after { .containerImages div { display: flex; flex-direction: column; - padding: 16px; - border-radius: 16px; - border: 1px solid #1f1f1f; gap: 8px; align-items: flex-start; + position: relative; } .containerImages div input { @@ -996,15 +1092,15 @@ tr.rowStartgebuer::after { } .containerImages div img { - max-height: 200px; - max-width: 200px; object-fit: contain; border-radius: 6px; - border: 1px solid var(--bg-top); + border: 1px solid #000000; } div.tableWraperOverflowY { + width: 100%; overflow-x: auto; + display: block; /* Prevent scroll chaining to body */ overscroll-behavior-x: contain; @@ -1039,4 +1135,42 @@ select { select:open { background-image: url("data:image/svg+xml;utf8,\\\"); +} + +.firstDiv { + background: #ff9cde; + background: linear-gradient(151deg, rgba(255, 156, 222, 1) 0%, rgb(255 110 110) 50%, rgba(255, 182, 130, 1) 100%); +} + +.firstDiv span { + color: #fff1fa !important; +} + +.firstDiv h3 { + color: #ffffff !important; +} + +.secondDiv { + background: #e0f7ff; + background: linear-gradient(150deg,rgba(224, 247, 255, 1) 0%, rgba(158, 226, 255, 1) 50%, rgba(182, 207, 252, 1) 100%); +} + +.secondDiv span { + color: #171797 !important; +} + +.secondDiv h3 { + color: #0f0f61 !important; +} + +.settingsRowGroup { + display: grid; + gap: 18px; +} +span.light { + font-weight: 300; +} + +.tableNoten input { + width: fit-content !important; } \ No newline at end of file diff --git a/www/intern/css/kampfrichter.css b/www/intern/css/kampfrichter.css index f81b169..f302acb 100644 --- a/www/intern/css/kampfrichter.css +++ b/www/intern/css/kampfrichter.css @@ -444,6 +444,7 @@ input[type="number"]::-webkit-outer-spin-button { display: inline-flex; align-items: center; justify-content: center; + align-self: baseline; } /* Variants */ @@ -460,13 +461,14 @@ input[type="number"]::-webkit-outer-spin-button { color: #781467; } -.submit-display-start, +.submit-display-start.start, .submit-musik-start { background: #ecfdf3; color: #15803d; border: 1px solid #4ade80; } +.submit-display-start.stopp, .submit-musik-stopp { background: #fef2f2; color: #b91c1c; @@ -921,7 +923,27 @@ table.widefat { justify-content: space-around; } - + +.editUserButtons { + display: flex; +} + +.div-submit-display-result, .div-submit-display-start { + display: flex; + flex-direction: column; +} + +.allNotentable { + display: flex; + flex-direction: row; + gap: 3rem; +} + +.singleNotentable { + display: flex; + flex-direction: column; + gap: 1rem; +} select { appearance: none; diff --git a/www/intern/css/logindata.css b/www/intern/css/logindata.css index b8aec1d..93f9e0d 100644 --- a/www/intern/css/logindata.css +++ b/www/intern/css/logindata.css @@ -32,6 +32,10 @@ "ROND" 0; } +.hidden { + display: none !important; +} + html, body, section { @@ -121,6 +125,7 @@ input { font-size: 0.95rem; font-weight: 500; cursor: pointer; + height: 39px; transition: all 0.25s ease; } @@ -155,7 +160,8 @@ h3.benutzer { /* ── User / Verein card ───────────────────────────────── */ -.single_pwedit { +.single_pwedit, +.newUserLink { background: var(--card-bg); border-radius: var(--card-radius); box-shadow: var(--card-shadow); @@ -163,24 +169,28 @@ h3.benutzer { transition: box-shadow 0.25s ease; } -.single_pwedit:hover { +.single_pwedit:hover, +.newUserLink:hover { box-shadow: 0 14px 40px rgba(15, 23, 42, 0.12); } -.single_pwedit.verein { +.single_pwedit.verein, +.newUserLink.verein { border-left: 4px solid var(--bg-top); } /* ── Form fields inside user card ─────────────────────── */ -.single_pwedit form { +.single_pwedit form, +.newUserLink form { display: flex; flex-wrap: wrap; gap: 14px 24px; align-items: flex-end; } -.single_pwedit label { +.single_pwedit label, +.newUserLink label { display: block; font-size: 0.8rem; font-weight: 500; @@ -190,12 +200,14 @@ h3.benutzer { margin-bottom: 5px; } -.single_pwedit .field-group { +.single_pwedit .field-group, +.newUserLink .field-group { flex: 1 1 200px; min-width: 0; } -.single_pwedit input[type="text"] { +.single_pwedit input[type="text"], +.newUserLink input[type="text"] { width: 100%; padding: 9px 12px; border: 1px dashed #999; @@ -207,20 +219,23 @@ h3.benutzer { transition: border-color 0.2s ease, box-shadow 0.2s ease; } -.single_pwedit input[type="text"]:focus { +.single_pwedit input[type="text"]:focus, +.newUserLink input[type="text"]:focus { outline: none; border: 1px solid var(--bg-top); box-shadow: 0 0 0 3px rgba(var(--bg-top-raw) / 0.12); } -.single_pwedit input[type="text"]::placeholder { +.single_pwedit input[type="text"]::placeholder, +.newUserLink input[type="text"]::placeholder { color: #b0b0b0; font-style: italic; } /* ── Buttons inside cards ─────────────────────────────── */ -.single_pwedit button[type="submit"] { +.single_pwedit button[type="submit"], +.newUserLink button[type="submit"] { appearance: none; border: 1px solid #7777778e; background: #7777778e; @@ -234,7 +249,8 @@ h3.benutzer { white-space: nowrap; } -.single_pwedit button[type="submit"]:hover { +.single_pwedit button[type="submit"]:hover, +.newUserLink button[type="submit"]:hover { background: var(--bg-top); border-color: var(--bg-top); color: #fff; @@ -284,6 +300,26 @@ h3.benutzer { color: var(--bg-top); } +.bgNewUserLink { + position: fixed; + top: 0; + left: 0; + height: 100dvh; + width: 100dvw; + display: flex; + align-items: center; + justify-content: center; + background-color: #39393941; + backdrop-filter: blur(2px); +} + +.newUserLink { + max-width: 600px; + max-height: 500px; + overflow-y: auto; + z-index: 9999; +} + /* ── Permission dropdown ──────────────────────────────── */ .perm-section { diff --git a/www/intern/css/otl.css b/www/intern/css/otl.css new file mode 100644 index 0000000..02a6a3e --- /dev/null +++ b/www/intern/css/otl.css @@ -0,0 +1,120 @@ +body{ + overflow: hidden; +} +.page-secure-login{ + display: flex; +} +.bg-picture-secure-login{ + width: calc(100vw - 450px); + height: 100vh; + position: absolute; + left: 0px; + top: 0px; +} +.bg-picture-secure-login img{ + width: 100%; + height: 100vh; + object-fit: cover; +} +.bg-secure-login{ + display: flex; + width: 100vw; + max-width: 450px; + height: 100vh; + background-color: #fff; + position: absolute; + right: 0px; + top: 0px; + align-items: center; + padding: 30px; +} +.bg-secure-login-form > h1{ + color: #000 !important; + font-size: 32px; +} +.bg-secure-login-form input[type=password], .bg-secure-login-form input[type=text]{ + padding: 5px; + width: 100%; + max-width: 300px; + border-top: none !important; + border-left: none !important; + border-right: none !important; + font-size: 16px; + border-bottom: 1px solid #000 !important; + border-radius: 0px !important; +} +.divShowPw:not(#lastDivShowPw) { + margin-bottom: 20px; +} + +.bg-secure-login-form input[type=password]:focus, .bg-secure-login-form input[type=text]:focus{ + outline: none; + border-bottom: 1px solid #000 !important; +} + +.bg-secure-login-form input[type=password]::placeholder, .bg-secure-login-form input[type=text]::placeholder { + color: #ccc !important; +} + +.bg-secure-login-form input[type=submit]{ + background-color: #fff !important; + padding: 10px 20px !important; + margin-top: 25px !important; + border: 1px solid #000 !important; + color: #000 !important; + transition: all 0.3s ease-out !important; + border-radius: 0px !important; +} + +body { + color: #000 !important; +} + +* { + box-sizing: border-box; +} + +.bg-secure-login-form input[type=submit]:hover{ + background-color: #000 !important; + color: #fff !important; +} +.bg-secure-login-form > p{ + margin-bottom: 30px; +} +.seclog_home_link{ + position: fixed; + z-index: 1000; + top: 30px; + right: 30px; +} +.divShowPw { + margin-top: 10px; + position: relative; + display: inline-block; + width: 100%; + max-width: 300px; +} +.togglePassword { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + background: none; + border: none; + cursor: pointer; + transition: all 0.5s ease; +} + +.togglePassword:hover { + transform: translateY(-50%) scale(1.15); +} + +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:focus, +input:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 1000px #ffffff inset !important; + box-shadow: 0 0 0 1000px #ffffff inset !important; + -webkit-text-fill-color: #000000 !important; + transition: background-color 5000s ease-in-out 0s; +} \ No newline at end of file diff --git a/www/intern/css/sidebar.css b/www/intern/css/sidebar.css index 4a9932c..98c14e4 100644 --- a/www/intern/css/sidebar.css +++ b/www/intern/css/sidebar.css @@ -1,10 +1,13 @@ /* ─── Sidebar Navigation ─── */ :root { --sidebar-width: 280px; - --sidebar-bg: #fafafa; - --sidebar-text: #363636; - --sidebar-hover: rgb(var(--bg-top-raw) / 0.2); - --sidebar-active: rgb(var(--bg-top-raw) / 0.35); + --sidebar-bg: #111218; + /* Dark navy / charcoal */ + --sidebar-text: #A0A0A0; + /* Soft grey text */ + --sidebar-hover: rgba(255, 255, 255, 0.05); + /* Subtile hover effect */ + --sidebar-active: rgba(255, 255, 255, 0.1); --sidebar-transition: 0.35s cubic-bezier(0.4, 0, 0.2, 1); } @@ -18,15 +21,16 @@ background: var(--sidebar-bg); z-index: 10000; transform: translateX(-100%); - transition: transform var(--sidebar-transition); + transition: transform var(--sidebar-transition), box-shadow var(--sidebar-transition); display: flex; flex-direction: column; overflow-y: auto; - box-shadow: 4px 0 24px rgba(0, 0, 0, 0.25); + box-shadow: none; } .sidebar-nav.open { transform: translateX(0); + box-shadow: 4px 0 24px rgba(0, 0, 0, 0.25); } /* Sidebar Header */ @@ -42,7 +46,7 @@ margin: 0; font-size: 16px; font-weight: 600; - color: #111; + color: #FFFFFF; letter-spacing: 0.5px; } @@ -69,7 +73,7 @@ font-weight: 700; text-transform: uppercase; letter-spacing: 1.2px; - color: rgba(45, 45, 45, 0.35); + color: rgba(255, 255, 255, 0.35); } /* Links */ @@ -95,13 +99,13 @@ .sidebar-links a:hover { background: var(--sidebar-hover); - color: #222; + color: #FFFFFF; } .sidebar-links a.active { background: var(--sidebar-active); - color: #111; - border-left-color: var(--bg-top); + color: #FFFFFF; + border-left-color: var(--accent); } .sidebar-links a svg { @@ -134,18 +138,18 @@ /* Hamburger Toggle */ .sidebar-toggle { - background: var(--sidebar-bg); + background: #FFFFFF; border: none; - border-radius: 10px; - width: 44px; - height: 44px; + border-radius: 50%; + width: 48px; + height: 48px; cursor: pointer; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; - box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); transition: all var(--sidebar-transition); padding: 0; } @@ -174,9 +178,9 @@ /* Footer */ .sidebar-footer { padding: 16px 24px; - border-top: 1px solid rgba(42, 42, 42, 0.222); + border-top: 1px solid rgba(255, 255, 255, 0.08); font-size: 11px; - color: rgba(42, 42, 42, 0.485); + color: rgba(255, 255, 255, 0.4); } .menuWrapper { diff --git a/www/intern/img/icon.png b/www/intern/img/icon.png index 086ccf4..6a64b0c 100644 Binary files a/www/intern/img/icon.png and b/www/intern/img/icon.png differ diff --git a/www/intern/js/sidebar.js b/www/intern/js/sidebar.js index 121d29f..76f9bc9 100644 --- a/www/intern/js/sidebar.js +++ b/www/intern/js/sidebar.js @@ -54,8 +54,9 @@ function changeFreigabe(freigabe) { const params = new URLSearchParams(); params.append('freigabe', freigabe); params.append('type', siteType); + params.append('csrf_token', window.CSRF_TOKEN); - fetch('/intern/scripts/kampfrichter/ajax/ajax-update_selected_kampfrichter.php', { + fetch('/intern/scripts/ajax-update_selected_freigabe.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params diff --git a/www/intern/kampfrichter.php b/www/intern/kampfrichter.php index d85d2ee..3360d78 100644 --- a/www/intern/kampfrichter.php +++ b/www/intern/kampfrichter.php @@ -53,11 +53,13 @@ $baseDir = $_SERVER['DOCUMENT_ROOT']; $reldirbase = "/../"; - if (session_status() !== PHP_SESSION_ACTIVE) { - session_start(); - } + require_once $baseDir . '/../scripts/session_functions.php'; - $access_granted_kampfrichter = $_SESSION['access_granted_kampfrichter'] ?? false; + ini_wkvs_session(true); + + $csrf_token = $_SESSION['csrf_token'] ?? ''; + + $access_granted_kampfrichter = check_user_permission('kampfrichter', true) ?? false; if (!$access_granted_kampfrichter) : @@ -72,7 +74,6 @@ $baseDir = $_SERVER['DOCUMENT_ROOT']; require $baseDir . '/../scripts/db/db-functions.php'; require $baseDir . '/../scripts/db/db-tables.php'; - require $baseDir . '/../scripts/csrf_functions.php'; require $baseDir . '/../scripts/websocket/ws-create-token.php'; @@ -106,7 +107,9 @@ $baseDir = $_SERVER['DOCUMENT_ROOT']; $sortprio = ['ep', 'p1', 'p1 kader', 'p2', 'p2 kader']; - $programmes = db_select($mysqli, $tableProgramme, 'programm', 'aktiv = ?', ['1']); + $programmes = db_select($mysqli, $tableProgramme, 'programm, `id`', 'aktiv = ?', ['1']); + + $indexedProgrammes = array_column($programmes, 'id', 'programm'); $focus_view_admin = $_SESSION['abtViewAdmin'] ?? false; $aktabtdb = db_get_var($mysqli, "SELECT value FROM $tableVar WHERE name = ?", ['wk_panel_current_abt']); @@ -117,6 +120,8 @@ $baseDir = $_SERVER['DOCUMENT_ROOT']; $notenConfig = $res->fetch_all(MYSQLI_ASSOC); + $indexedNotenNames = array_column($notenConfig, 'name', 'id'); + // var_dump($notenConfig); //$dbprogramme = db_select($mysqli, $tableTurnerinnen, '*', 'abteilung = ? AND (bezahlt = ? OR bezahlt = ?)', [$aktabt, '2', '5'], 'id ASC'); @@ -223,26 +228,20 @@ $baseDir = $_SERVER['DOCUMENT_ROOT'];

Aktuelle Abt.

+

+

/

- - - - - - */ - - } else { + Aktuelle Gruppe

'; ?>
+

+
@@ -309,7 +310,7 @@ $baseDir = $_SERVER['DOCUMENT_ROOT']; } } - $kampfrichter = db_select($mysqli, $tableInternUsers, 'id, username, freigabe', '', [], 'username ASC' ); + $kampfrichter = db_select($mysqli, $tableInternUsers, 'id, name_person, freigabe', '', [], 'name_person ASC' ); $filteredKampfrichter = []; @@ -340,11 +341,11 @@ $baseDir = $_SERVER['DOCUMENT_ROOT']; data-user="' . $selecteduser . '">'; echo ''; foreach ($filteredKampfrichter as $person) { - $selected = $selectedKampfrichter[$i] === $person['username'] + $selected = $selectedKampfrichter[$i] === $person['name_person'] ? 'selected' : ''; - echo ''; + echo ''; } echo ''; @@ -356,13 +357,16 @@ $baseDir = $_SERVER['DOCUMENT_ROOT']; if ($selecteduser === 'admin'){ $valuetogglemodeadmin = ($focus_view_admin == true) ? 'nach Programmen sortieren (Admin)' : 'nach Abteilungen sortieren (Admin)'; $styletoggleadmin = ($focus_view_admin == true) ? 'background-color: #003;' : 'background-color: #030;'; + + ?> - echo '
'; - echo ''; - //wp_nonce_field('toggle_advanced_mode_admin_action', 'toggle_advanced_mode_admin_nonce'); - echo ''; - echo ''; - echo '
'; +
+ + + +
+ + Aktuelle Abteilung '.$aktabt.' von '.$maxvalue.' ('.htmlspecialchars(strtoupper($allprogrammeabtstrcleared)).')

CoP 2025-2028STV 2025-2028'; @@ -630,12 +634,13 @@ $baseDir = $_SERVER['DOCUMENT_ROOT']; $arrayNameMap = array_change_key_case(array_column($disciplines, 'id', 'name'), CASE_LOWER); $itemsToLoop[] = ['name' => $selecteduser, 'id' => $arrayNameMap[$selecteduser] ?? null]; } - // var_dump($itemsToLoop); + + $indexedDisciplines = array_column($disciplines, 'name', 'id'); ?>