First version, for githup; UNSTABLE, DO NOT USE!

This commit is contained in:
Fabio Herzig
2026-04-12 21:25:44 +02:00
commit a51fd9dbeb
423 changed files with 58560 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
<?php
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https://" : "http://";
$domain = $_SERVER['HTTP_HOST'];
$url = $protocol . $domain;
if ((isset($_POST['prev_abt'])) && !empty($_POST['prev_abt_submit'])) {
$value = get_option('wk_panel_current_abt', 1);
if ($value > 1){
$value -= 1;
update_option('wk_panel_current_abt', $value);
}
header("Location: ".$url."/intern/kampfrichter".$_SERVER['REQUEST_URI']);
exit;
}
if ((isset($_POST['next_abt'])) && !empty($_POST['next_abt_submit'])) {
$value = get_option('wk_panel_current_abt', 1);
$maxvalue = $wpdb->get_var( "SELECT abteilung FROM $table_name ORDER BY abteilung DESC LIMIT 1" );
if ($value < $maxvalue){
$value += 1;
update_option('wk_panel_current_abt', $value);
}
header("Location: ".$url."/intern/kampfrichter".$_SERVER['REQUEST_URI']);
exit;
}
if (!isset($_SESSION['currentsubabt'])){
$_SESSION['currentsubabt'] = 0;
}
if (!isset($_SESSION['last_abt'])){
$_SESSION['last_abt'] = get_option('wk_panel_current_abt', 1);
}
if ($_SESSION['last_abt'] !== get_option('wk_panel_current_abt', 1)){
$_SESSION['currentsubabt'] = 0;
$_SESSION['last_abt'] = get_option('wk_panel_current_abt', 1);
}
if ((isset($_POST['prev_subabt'])) && !empty($_POST['prev_subabt_submit'])) {
$value = $_SESSION['currentsubabt'];
if ($value > 0){
$_SESSION['currentsubabt']--;
$_SESSION['last_abt'] = get_option('wk_panel_current_abt', 1);
}
header("Location: ".$url."/intern/kampfrichter");
exit;
}
if ((isset($_POST['next_subabt'])) && !empty($_POST['next_subabt_submit'])) {
$value = $_SESSION['currentsubabt'];
if ($value < 4){
$_SESSION['currentsubabt']++;
$_SESSION['last_abt'] = get_option('wk_panel_current_abt', 1);
}
header("Location: ".$url."/intern/kampfrichter");
exit;
}
if (
isset($_POST['togle_advanced_mode']) &&
!empty($_POST['togle_advanced_mode_submit']) &&
check_admin_referer('toggle_advanced_mode_action', 'toggle_advanced_mode_nonce')
) {
$current_value = get_option('option_advanced_mode', false);
$new_value = !$current_value;
update_option('option_advanced_mode', $new_value);
hheader("Location: ".$url."/intern/kampfrichter".$_SERVER['REQUEST_URI']);
exit;
}
if (
isset($_POST['togle_advanced_mode_admin']) &&
!empty($_POST['togle_advanced_mode_admin_submit']) &&
check_admin_referer('toggle_advanced_mode_admin_action', 'toggle_advanced_mode_admin_nonce')
) {
$current_value = get_option('option_advanced_mode_admin', false);
$new_value = !$current_value;
update_option('option_advanced_mode_admin', $new_value);
header("Location: ".$url."/intern/kampfrichter".$_SERVER['REQUEST_URI']);
exit;
}

View File

@@ -0,0 +1,28 @@
<?php
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (
!((isset($_SESSION['access_granted_wk_leitung']) && $_SESSION['access_granted_wk_leitung'] === true) ||
(isset($_SESSION['access_granted_kampfrichter']) && $_SESSION['access_granted_kampfrichter'] === true))
) {
http_response_code(403);
exit;
}
if (!isset($_POST['access'])) {
http_response_code(400);
exit;
}
$access = preg_replace("/[\W]/", "", trim($_POST['access']));
$baseDir = $_SERVER['DOCUMENT_ROOT'];
require $baseDir . "/../scripts/websocket/ws-create-token.php";
$token = generateWSToken($access);
$responseBool = $token != null;
echo json_encode(['success' => $responseBool, 'token' => $token]);

View File

@@ -0,0 +1,4 @@
upload_max_filesize = 50M
post_max_size = 55M
max_execution_time = 120
max_input_time = 120

View File

@@ -0,0 +1,142 @@
<?php
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
$isTrainer =
isset($_SESSION['access_granted_trainer'], $_SESSION['passcodetrainer_id']) &&
$_SESSION['access_granted_trainer'] === true &&
(int)$_SESSION['passcodetrainer_id'] > 0;
$isWkLeitung =
isset($_SESSION['access_granted_wk_leitung'], $_SESSION['passcodewk_leitung_id']) &&
$_SESSION['access_granted_wk_leitung'] === true &&
(int)$_SESSION['passcodewk_leitung_id'] > 0;
if (!$isTrainer && !$isWkLeitung) {
http_response_code(403);
exit;
}
// Allow large uploads and enough memory for GD processing
ini_set('memory_limit', '256M');
ini_set('max_execution_time', '120');
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
if (!isset($_FILES['music_file']) || $_FILES['music_file']['error'] !== UPLOAD_ERR_OK) {
echo json_encode([
'success' => false,
'message' => 'Keine Musik' . $_FILES['music_file']['error'] ?? 'NO ERROR KNOWN'
]);
exit;
}
$type = ($isTrainer) ? 'tr' : 'wkl';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/db/db-functions.php';
$saveDir = '/files/music/';
$normalDir = $saveDir;
$uploadDir = $baseDir . $saveDir;
$maxLengthMusic = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['maxLengthMusic']);
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$tmpPath = $_FILES['music_file']['tmp_name'];
$originalName = $_FILES['music_file']['name'];
$extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
$allowedExt = ['mp3', 'wav', 'ogg'];
if (!in_array($extension, $allowedExt, true)) {
echo json_encode(['success' => false, 'message' => 'Falsches Format (Endung)']);
http_response_code(422);
exit;
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($tmpPath);
$allowedMime = ['audio/mpeg', 'audio/wav', 'audio/x-wav', 'audio/ogg', 'application/ogg'];
if (!in_array($mimeType, $allowedMime, true)) {
echo json_encode(['success' => false, 'message' => 'Dateiinhalt ist kein gültiges Audio']);
http_response_code(422);
exit;
}
$filename = uniqid('userupload_', true) . '.' . $extension;
$destination = $uploadDir . $filename;
$normalPath = $normalDir . $filename;
if (!move_uploaded_file($tmpPath, $destination)) {
http_response_code(500);
exit;
}
if ($isTrainer && $maxLengthMusic !== null && intval($maxLengthMusic) !== 0) {
require $baseDir . '/../composer/vendor/autoload.php';
$getID3 = new getID3;
$fileInfo = $getID3->analyze($destination);
if (empty($fileInfo['playtime_seconds'])) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Fehler beim Bestimmen der Musiklänge'
]);
exit;
}
$duration = (float) $fileInfo['playtime_seconds'];
if ($duration > intval($maxLengthMusic)) {
unlink($destination);
echo json_encode([
'success' => false,
'message' => 'Musik zu lange (über ' . intval($maxLengthMusic) . ' Sekunden)'
]);
http_response_code(422);
exit;
}
}
$sql = "INSERT INTO $tableAudiofiles (`file_name`,`file_path`) VALUES (?, ?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("ss", $originalName, $normalPath);
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$id = $mysqli->insert_id;
$stmt->close();
echo json_encode([
'success' => true,
'id' => $id,
'filename' => $originalName,
'filepath' => $normalPath
]);

View File

@@ -0,0 +1,10 @@
-- 1. Update the Noten table to include run_number
-- NOTE: We also update the PRIMARY KEY to include this new column
ALTER TABLE `a4b9577448d6_noten`
ADD COLUMN `run_number` TINYINT(3) UNSIGNED NOT NULL DEFAULT 1 AFTER `jahr`,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`person_id`, `note_bezeichnung_id`, `geraet_id`, `jahr`, `run_number`);
-- 2. Update the configuration table to support program-specific run counts
ALTER TABLE `a4b9577448d6_noten_bezeichnungen`
ADD COLUMN `anzahl_laeufe_json` TEXT NULL DEFAULT NULL AFTER `pro_geraet`;

View File

@@ -0,0 +1,68 @@
<?php
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
// ---------- Get and sanitize input ----------
$type = isset($_GET['type']) ? preg_replace('/[^a-zA-Z0-9 _-]/', '', $_GET['type']) : '';
$allowed_types = ['logo','scoring','ctext'];
if (!in_array($type, $allowed_types)) {
echo json_encode(['success' => false, 'message' => 'Invalid type']);
exit;
}
if ($type === 'ctext'){
$ctext = isset($_GET['ctext']) ? $_GET['ctext'] : '';
}
$folder = realpath($baseDir.'/displays/json');
if ($folder === false) {
echo json_encode([
'success' => false,
'message' => 'Could not find displays folder.'
]);
exit;
}
$filename = 'config.json';
$filepath = $folder . '/' . $filename;
if (!is_writable($folder)) {
echo json_encode(['success' => false, 'message' => 'Folder not writable: ' . $folder]);
exit;
}
$jsonString = file_get_contents($filepath);
// decode JSON, fallback to empty array if invalid
$oldjson = json_decode($jsonString, true) ?? [];
$oldjson["type"] = $type;
if ($type === 'ctext'){
$oldjson["ctext"] = $ctext;
}
$jsonData = json_encode($oldjson);
// Write file
if (file_put_contents($filepath, $jsonData) === false) {
echo json_encode([
'success' => false,
'message' => 'Failed to write JSON file: ' . $filepath
]);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'JSON type updated',
'disable_start_button' => true
]);
exit;

View File

@@ -0,0 +1,89 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
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;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$allowedTypes = [
'wkName',
'displayColourLogo',
'displayTextColourLogo',
'displayColorScoringBg',
'displayColorScoringBgSoft',
'displayColorScoringPanel',
'displayColorScoringPanelSoft',
'displayColorScoringPanelText',
'displayColorScoringPanelTextSoft',
'displayColorScoringPanelTextNoteL',
'displayColorScoringPanelTextNoteR',
'displayIdNoteL',
'displayIdNoteR',
'rechnungenName',
'rechnungenVorname',
'rechnungenStrasse',
'rechnungenHausnummer',
'rechnungenPostleitzahl',
'rechnungenOrt',
'rechnungenIBAN',
'maxLengthMusic',
'linkWebseite',
'rangNote',
'orderBestRang'
];
$type = $_POST['type'] ? trim($_POST['type']) : '';
if (!in_array($type, $allowedTypes)) {
echo json_encode(['success' => false, 'message' => 'Invalid input']);
exit;
}
$value = $_POST['value'] ? trim($_POST['value']) : null;
// ---------- Step 2: Get values from DB ----------
$stmt = $mysqli->prepare("INSERT INTO $tableVar (`name`, `value`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)");
if (!$stmt) {
echo json_encode(['success' => false, 'message' => 'Critical db error']);
exit;
}
$stmt->bind_param("ss", $type, $value);
$success = $stmt->execute();
$stmt->close();
if (!$success) {
echo json_encode(['success' => false, 'message' => 'Insert failed']);
exit;
}
// Return JSON
echo json_encode([
'success' => true
]);
exit;

View File

@@ -0,0 +1,84 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
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;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/csrf_functions.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo json_encode(['success' => false, 'message' => 'Critical DB Error.']);
exit;
}
$action = $_POST['action'] ?? '';
if ($action === 'add') {
$name = trim($_POST['name'] ?? '');
$start_index = intval($_POST['start_index'] ?? 0);
$color = trim($_POST['color'] ?? '#424242');
if (!$name) {
echo json_encode(['success' => false, 'message' => 'Name ist erforderlich.']);
exit;
}
$stmt = $mysqli->prepare("INSERT INTO $tableGeraete (name, start_index, color_kampfrichter) VALUES (?, ?, ?)");
$stmt->bind_param("sis", $name, $start_index, $color);
$success = $stmt->execute();
$new_id = $mysqli->insert_id;
$stmt->close();
if ($success) {
echo json_encode(['success' => true, 'id' => $new_id]);
} else {
echo json_encode(['success' => false, 'message' => 'Fehler beim Hinzufügen.']);
}
} elseif ($action === 'update') {
$id = intval($_POST['id'] ?? 0);
$field = $_POST['field'] ?? '';
$value = $_POST['value'] ?? '';
$allowedFields = ['name', 'start_index', 'color_kampfrichter'];
if ($id > 0 && in_array($field, $allowedFields)) {
if ($field === 'start_index') {
$value = intval($value);
}
$updated = db_update($mysqli, $tableGeraete, [$field => $value], ['id' => $id]);
if ($updated !== false) {
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'message' => 'DB Update failed.']);
}
} else {
echo json_encode(['success' => false, 'message' => 'Invalid parameters.']);
}
} elseif ($action === 'delete') {
$id = intval($_POST['id'] ?? 0);
if ($id > 0) {
db_delete($mysqli, $tableGeraete, ['id' => $id]);
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'message' => 'Invalid ID.']);
}
} else {
echo json_encode(['success' => false, 'message' => 'Action not found.']);
}

View File

@@ -0,0 +1,261 @@
<?php
header('Content-Type: application/json');
ini_set("display_errors", 1);
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
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;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/csrf_functions.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo json_encode(['success' => false, 'message' => 'Critical DB Error.']);
exit;
}
$recalculateJSONs = false;
$action = $_POST['action'] ?? '';
if ($action === 'add') {
$name = trim($_POST['name'] ?? '');
$type_val = $_POST['type_val'] ?? 'input';
$berechnung = trim($_POST['berechnung'] ?? '');
$pro_geraet = intval($_POST['pro_geraet'] ?? 0);
$default_value = (isset($_POST['default_value'])) ? floatval($_POST['default_value']) : null;
$min_value = (isset($_POST['min_value'])) ? floatval($_POST['min_value']) : null;
$max_value = (isset($_POST['max_value'])) ? floatval($_POST['max_value']) : null;
$id = (isset($_POST['id'])) ? floatval($_POST['id']) : 1;
if (!$id) {
echo json_encode(['success' => false, 'message' => 'Id ist erforderlich.']);
exit;
}
$stmt = $mysqli->prepare("SELECT 1 FROM $tableNotenBezeichnungen WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
echo json_encode([
'success' => false,
'message' => 'Eine Note mit dieser Id existiert bereits.'
]);
$stmt->close();
exit;
}
$stmt->close();
if (!$name) {
echo json_encode(['success' => false, 'message' => 'Name ist erforderlich.']);
exit;
}
$stmt = $mysqli->prepare("INSERT INTO $tableNotenBezeichnungen (id, name, type, berechnung, pro_geraet, default_value, min_value, max_value) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->bind_param("isssisss", $id, $name, $type_val, $berechnung, $pro_geraet, $default_value, $min_value, $max_value);
$success = $stmt->execute();
$new_id = $mysqli->insert_id;
$stmt->close();
$recalculateJSONs = true;
if ($success) {
if (!$recalculateJSONs) { echo json_encode(['success' => true, 'id' => $new_id]); }
} else {
echo json_encode(['success' => false, 'message' => 'Fehler beim Hinzufügen.']);
exit;
}
} elseif ($action === 'update') {
$id = intval($_POST['id'] ?? 0);
$field = $_POST['field'] ?? '';
$value = $_POST['value'] ?? '';
$allowedFields = ['name', 'type', 'berechnung', 'pro_geraet', 'geraete_json', 'anzahl_laeufe_json', 'default_value', 'min_value', 'max_value', 'zeige_in_tabelle', 'zeige_in_tabelle_mobile', 'zeige_in_tabelle_admin', 'zeige_auf_rangliste', 'nullstellen', 'prefix_display'];
if ($id > 0 && in_array($field, $allowedFields)) {
if ($field === 'pro_geraet') {
$value = intval($value);
}
if ($field === 'berechnung' || $field === 'type') {
$recalculateJSONs = true;
}
$updated = db_update($mysqli, $tableNotenBezeichnungen, [$field => $value], ['id' => $id]);
if ($updated !== false) {
if (!$recalculateJSONs) { echo json_encode(['success' => true]); }
} else {
echo json_encode(['success' => false, 'message' => 'DB Update failed.']);
exit;
}
} else {
echo json_encode(['success' => false, 'message' => 'Invalid parameters.']);
exit;
}
} elseif ($action === 'delete') {
$id = intval($_POST['id'] ?? 0);
if ($id > 0) {
db_delete($mysqli, $tableNotenBezeichnungen, ['id' => $id]);
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'message' => 'Invalid ID.']);
}
} else {
echo json_encode(['success' => false, 'message' => 'Action not found.']);
exit;
}
if ($recalculateJSONs) {
$noten = db_select($mysqli, $tableNotenBezeichnungen, "id, berechnung, type");
// 1. Re-index the array so the keys match the database IDs
$notenById = array_column($noten, null, 'id');
$berechnungen = [];
foreach ($notenById as $id => $sn) {
if ($sn['type'] === 'berechnung') {
$berechnungen[] = $sn;
}
}
if (empty($berechnungen)) {
echo json_encode(['success' => true, 'message' => "Keine Berechnungen ausgewählt"]);
exit;
}
require $baseDir . "/../scripts/string-calculator/string-calculator-functions.php";
$notenRechner = new NotenRechner();
// 1. Build the direct map
// Format: [ Changed_Note_ID => [ "CalcId|GeraetId" => [CalcId, GeraetId] ] ]
$dependencyMap = [];
foreach ($berechnungen as $calc) {
$neededIdsArray = $notenRechner->getBenoetigteIdsComplex($calc['berechnung']);
if (empty($neededIdsArray)) {
continue;
}
$calcId = (int)$calc['id'];
foreach ($neededIdsArray as $needed) {
$nId = (int)$needed['noteId'];
// Keep geraetId as integer if it's a number (e.g., 3), otherwise string ('S')
$gId = is_numeric($needed['geraetId']) ? (int)$needed['geraetId'] : $needed['geraetId'];
// Create a unique string key so we don't store exact duplicates
$nodeKey = $calcId . '|' . $gId;
if (!isset($dependencyMap[$nId])) {
$dependencyMap[$nId] = [];
}
// Store it as the "little array" you requested: [DependentCalcId, GeraetId]
$dependencyMap[$nId][$nodeKey] = [$calcId, $gId];
}
}
// 2. Our recursive helper function (Updated for complex nodes)
function getCompleteDependencyChain($id, $directMap, $visited = [])
{
// If this ID doesn't have anything depending on it, return empty
if (!isset($directMap[$id])) {
return [];
}
$allDependencies = [];
foreach ($directMap[$id] as $nodeKey => $complexNode) {
// CIRCULAR DEPENDENCY CHECK:
// We check against the string key (e.g., "10|S") to prevent infinite loops
if (isset($visited[$nodeKey])) {
continue;
}
// 1. Mark this specific node as visited
$visited[$nodeKey] = true;
// 2. Add the little array [CalcId, GeraetId] to our master list
$allDependencies[$nodeKey] = $complexNode;
// 3. Recursively find everything that depends on THIS calculation ID
// $complexNode[0] is the dependent Calc ID
$childDependencies = getCompleteDependencyChain($complexNode[0], $directMap, $visited);
// 4. Merge the child results into our master list safely
foreach ($childDependencies as $childKey => $childNode) {
$allDependencies[$childKey] = $childNode;
$visited[$childKey] = true; // Ensure the parent loop knows this was visited
}
}
return $allDependencies;
}
// 3. Create the final flattened map for ALL IDs
$flatDependencyMap = [];
foreach (array_keys($notenById) as $id) {
$chain = getCompleteDependencyChain($id, $dependencyMap);
// Only add it if dependencies exist
if (!empty($chain)) {
// array_values() removes the "10|S" string keys, turning it into a perfect
// 0-indexed array for clean JSON encoding: [[10, "S"], [12, 3]]
$flatDependencyMap[$id] = array_values($chain);
}
}
// 4. Database Updates
// Step 1: Reset all rows to NULL in a single query
$resetSql = "UPDATE $tableNotenBezeichnungen SET `berechnung_json` = NULL";
$mysqli->query($resetSql);
// Step 2: Prepare the statement
$updateSql = "UPDATE $tableNotenBezeichnungen SET `berechnung_json` = ? WHERE id = ?";
$stmt = $mysqli->prepare($updateSql);
foreach ($flatDependencyMap as $id => $completeDependencyArray) {
if (empty($completeDependencyArray)) {
continue;
}
$jsonString = json_encode($completeDependencyArray);
// Bind parameters: 's' for string (JSON), 'i' for integer (ID)
$stmt->bind_param("si", $jsonString, $id);
$stmt->execute();
}
$stmt->close();
echo json_encode(['success' => true, 'message' => "Abhaengigkeiten berechnet"]);
exit;
}

View File

@@ -0,0 +1,204 @@
<?php
/**
* Upload Image API
* Accepts multipart/form-data POST with 'image' file.
* Converts JPG/PNG to WebP (resized to max 2400px), saves to /files/img/admin_upload/{uid}.webp
* Returns JSON: { success: true }
*/
// Allow large uploads and enough memory for GD processing
ini_set('memory_limit', '256M');
ini_set('upload_max_filesize', '50M');
ini_set('post_max_size', '55M');
ini_set('max_execution_time', '120');
const MAX_DIMENSION = 2400;
const MAX_DIMENSION_ICON = 1000;
const WEBP_QUALITY = 80;
$baseDir = $_SERVER['DOCUMENT_ROOT'];
header('Content-Type: application/json');
session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
$baseDir = $_SERVER['DOCUMENT_ROOT'];
// Only accept POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Method not allowed']);
exit;
}
$allowedTypes = ['Kampfrichter', 'Trainer', 'Wk_leitung', 'Otl', 'icon', 'logo-normal'];
if (!isset($_POST['type']) || !in_array($_POST['type'], $allowedTypes)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Typ nicht angegeben oder nicht erlaubt']);
exit;
}
$pngs = ['icon', 'logo-normal'];
$type = $_POST['type'];
$isIcon = in_array($type, $pngs);
// Check if $_FILES is empty entirely (can happen if post_max_size exceeded)
if (empty($_FILES)) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'No files received. The file may exceed the server upload limit).',
]);
exit;
}
// Check specific file field
if (!isset($_FILES['image'])) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'No "image" field in upload. Received fields: ' . implode(', ', array_keys($_FILES)),
]);
exit;
}
if ($_FILES['image']['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
$errors = [
UPLOAD_ERR_INI_SIZE => 'File exceeds upload_max_filesize',
UPLOAD_ERR_FORM_SIZE => 'File exceeds form MAX_FILE_SIZE',
UPLOAD_ERR_PARTIAL => 'File was only partially uploaded',
UPLOAD_ERR_NO_FILE => 'No file was uploaded',
UPLOAD_ERR_NO_TMP_DIR => 'Missing temp directory',
UPLOAD_ERR_CANT_WRITE => 'Failed to write to disk',
];
$code = $_FILES['image']['error'];
$msg = $errors[$code] ?? "Unknown error code: $code";
echo json_encode(['success' => false, 'message' => $msg]);
exit;
}
$file = $_FILES['image'];
$tmpPath = $file['tmp_name'];
// Validate MIME type
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($tmpPath);
$allowedMimes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
if (!in_array($mime, $allowedMimes, true)) {
http_response_code(415);
echo json_encode(['success' => false, 'message' => "Unsupported file type: $mime"]);
exit;
}
// Target directory
if ($isIcon) {
$uploadDir = $baseDir . '/intern/img/';
} else {
$uploadDir = $baseDir . '/intern/img/login';
}
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
// Load image into GD
$srcImage = null;
switch ($mime) {
case 'image/jpeg':
$srcImage = @imagecreatefromjpeg($tmpPath);
break;
case 'image/png':
$srcImage = @imagecreatefrompng($tmpPath);
break;
case 'image/webp':
$srcImage = @imagecreatefromwebp($tmpPath);
break;
case 'image/gif':
$srcImage = @imagecreatefromgif($tmpPath);
break;
}
if (!$srcImage) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Failed to load image into GD. It may be corrupt or too large.']);
exit;
}
// ── Resize if needed ────────────────────────────────
$origW = imagesx($srcImage);
$origH = imagesy($srcImage);
$maxDimension = ($isIcon) ? MAX_DIMENSION_ICON : MAX_DIMENSION;
if ($origW > $maxDimension || $origH > $maxDimension) {
// Calculate new dimensions keeping aspect ratio
if ($origW >= $origH) {
$newW = $maxDimension;
$newH = intval(round($origH * ($maxDimension / $origW)));
} else {
$newH = $maxDimension;
$newW = intval(round($origW * ($maxDimension / $origH)));
}
$resized = imagecreatetruecolor($newW, $newH);
// Preserve transparency
imagealphablending($resized, false);
imagesavealpha($resized, true);
$transparent = imagecolorallocatealpha($resized, 0, 0, 0, 127);
imagefill($resized, 0, 0, $transparent);
imagecopyresampled($resized, $srcImage, 0, 0, 0, 0, $newW, $newH, $origW, $origH);
imagedestroy($srcImage);
$srcImage = $resized;
} else {
// Still preserve transparency
imagepalettetotruecolor($srcImage);
imagealphablending($srcImage, true);
imagesavealpha($srcImage, true);
}
if ($isIcon) {
// ── Save as PNG ────────────────────────────────────
$filename = $type . '.png';
$destPath = $uploadDir . '/' . $filename;
$webPath = '/intern/img/' . $filename;
$pngCompression = 6;
$success = imagepng($srcImage, $destPath, $pngCompression);
} else {
// ── Save as WebP ────────────────────────────────────
$filename = 'bg' . $_POST['type'] . '.webp';
$destPath = $uploadDir . '/' . $filename;
$webPath = '/intern/img/admin_upload/' . $filename;
$success = imagewebp($srcImage, $destPath, WEBP_QUALITY);
}
imagedestroy($srcImage);
if (!$success) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Failed to convert to WebP']);
exit;
}
echo json_encode([
'success' => true
]);

View File

@@ -0,0 +1,321 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', 1);
error_reporting(E_ALL);
session_start();
if (
empty($_SESSION['access_granted_kampfrichter']) ||
$_SESSION['access_granted_kampfrichter'] !== true ||
empty($_SESSION['passcodekampfrichter_id']) ||
intval($_SESSION['passcodekampfrichter_id']) < 1
) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require $baseDir . '/../scripts/csrf_functions.php';
if (!verify_csrf()) {
echo json_encode(['success' => false, 'message' => 'Forbidden']);
exit;
}
// Validate editId from POST
if (isset($_POST['editId'])) {
$editId = intval($_POST['editId']);
if ($editId === false || $editId < 1) {
echo json_encode(['success' => false, 'message' => 'Falsche Personen ID']);
exit;
}
}
$editId = filter_var($editId, FILTER_VALIDATE_INT);
if ($editId === false) {
echo json_encode(['success' => true]);
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if (!($data['success'] ?? false)) {
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
$isAdmin = (($_SESSION['selectedFreigabeKampfrichter'] ?? '') === 'admin') ? true : false;
$disciplines = db_select($mysqli, $tableGeraete, 'id', '', [], 'start_index ASC');
$disciplines = array_column($disciplines, "id");
if (!$isAdmin) {
$discipline = intval($_POST['geraet']) ?? 0;
if (!in_array($discipline, $disciplines)) {
echo json_encode(['success' => false, 'message' => 'Falsche Geräte ID']);
exit;
}
$disciplines = [$discipline];
$stmt = $mysqli->prepare("
SELECT
t.name,
t.vorname,
t.programm,
p.id as programm_id,
agg.abteilung,
agg.geraeteIndex,
agg.startIndex
FROM $tableTurnerinnen t
LEFT JOIN $tableProgramme p ON p.programm = t.programm
LEFT JOIN (
SELECT
ta.turnerin_id,
GROUP_CONCAT(DISTINCT a.name SEPARATOR ', ') AS abteilung,
GROUP_CONCAT(DISTINCT g.start_index SEPARATOR ', ') AS geraeteIndex,
ta.turnerin_index AS startIndex
FROM $tableTurnerinnenAbt ta
INNER JOIN $tableAbt a
ON a.id = ta.abteilung_id
LEFT JOIN $tableGeraete g
ON g.id = ta.geraet_id
GROUP BY ta.turnerin_id
) agg ON agg.turnerin_id = t.id
WHERE t.id = ?
");
} else {
$stmt = $mysqli->prepare("SELECT t.`name`, t.`vorname`, t.`programm`, p.id as programm_id FROM $tableTurnerinnen t LEFT JOIN $tableProgramme p ON p.programm = t.programm WHERE t.id = ?");
}
$stmt->bind_param('i', $editId);
$stmt->execute();
$result = $stmt->get_result();
$dbresult = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
if (!$dbresult || !is_array($dbresult) || count($dbresult) < 1) {
echo json_encode(['success' => false, 'message' => 'Falsche Personen ID']);
exit;
}
$now = new DateTime();
$jahr = ($now->format('n') > 6) ? $now->modify('+1 year')->format('Y') : $now->format('Y');
if ($isAdmin) {
$stmt = $mysqli->prepare("SELECT `note_bezeichnung_id`, `value`, `geraet_id`, `run_number` FROM $tableNoten WHERE `person_id` = ? AND `jahr` = ?");
$stmt->bind_param('ss', $editId, $jahr);
} else {
$stmt = $mysqli->prepare("SELECT `note_bezeichnung_id`, `value`, `geraet_id`, `run_number` FROM $tableNoten WHERE `person_id` = ? AND `geraet_id` = ? AND `jahr` = ?");
$stmt->bind_param('sss', $editId, $discipline, $jahr);
}
$stmt->execute();
$result = $stmt->get_result();
$notenDB = $result->fetch_all(MYSQLI_ASSOC);
$indexedNotenDB = [];
foreach ($notenDB as $sn) {
$indexedNotenDB[$sn['geraet_id']][$sn['note_bezeichnung_id']][$sn['run_number']] = $sn['value'];
}
$stmt->close();
$stmt = $mysqli->prepare("SELECT `id`, `default_value`, `nullstellen`, `pro_geraet`, `geraete_json`, `anzahl_laeufe_json` FROM $tableNotenBezeichnungen");
$stmt->execute();
$result = $stmt->get_result();
$notenConfig = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
$noten = [];
$row = $dbresult[0];
$programm_id = $row['programm_id'];
foreach ($disciplines as $d) {
foreach ($notenConfig as $snC) {
$allowedGeraete = !empty($snC['geraete_json']) ? json_decode($snC['geraete_json'], true) : [];
$isProGeraet = ($snC['pro_geraet'] === 1);
if (!$isProGeraet && !in_array($d, $allowedGeraete)) {
continue;
}
// Determine number of runs for this program
$anzRunsConfig = !empty($snC['anzahl_laeufe_json']) ? json_decode($snC['anzahl_laeufe_json'], true) : [];
$runs = $anzRunsConfig[$programm_id] ?? $anzRunsConfig['default'] ?? 1;
for ($r = 1; $r <= $runs; $r++) {
$value = $indexedNotenDB[$d][$snC['id']][$r] ?? $snC['default_value'] ?? 0;
$noten[$d][$snC['id']][$r] = number_format($value, $snC['nullstellen'] ?? 2);
}
}
}
$titel = $row['vorname'].' '.$row['name'].', '.$row['programm'];
if (!$isAdmin) {
// $entries = db_select($mysqli, $tableTurnerinnen, 'name, vorname, programm, id', 'abteilung = ? AND startgeraet = ?', [$row['abteilung'], $row['startgeraet']]);
$stmt = $mysqli->prepare("
SELECT
t.name,
t.vorname,
t.programm,
t.id,
agg.abteilung,
agg.geraeteIndex,
agg.startIndex
FROM $tableTurnerinnen t
LEFT JOIN (
SELECT
ta.turnerin_id,
GROUP_CONCAT(DISTINCT a.name SEPARATOR ', ') AS abteilung,
GROUP_CONCAT(DISTINCT g.start_index SEPARATOR ', ') AS geraeteIndex,
ta.turnerin_index AS startIndex
FROM $tableTurnerinnenAbt ta
INNER JOIN $tableAbt a
ON a.id = ta.abteilung_id
LEFT JOIN $tableGeraete g
ON g.id = ta.geraet_id
GROUP BY ta.turnerin_id
) agg ON agg.turnerin_id = t.id
WHERE agg.abteilung = ? AND agg.geraeteIndex = ?
ORDER BY t.id DESC
");
$bezahlt = 2;
$bezahltoverride = 5;
$stmt->bind_param('ss', $row['abteilung'], $row['geraeteIndex']);
$stmt->execute();
$result = $stmt->get_result();
$entries = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
if (!$entries || !is_array($entries) || count($entries) < 1) {
echo json_encode(['success' => false, 'message' => 'No DB Result for next Turnerin']);
exit;
}
$maxstartindex = count($entries);
if ($maxstartindex < 1) {
$maxstartindex = 1;
}
$csti = (int)$row['startIndex'];
$nsti = $csti + 1;
if ($nsti > $maxstartindex){
$nsti -= $maxstartindex;
}
$rohstartindex = intval($row['startIndex']);
$varstartgeraet = intval($row['geraeteIndex']);
$aktsubabt = $_SESSION['currentsubabt'];
foreach ($disciplines as $index => $sdiscipline) {
if (isset($sdiscipline) && $sdiscipline === $discipline) {
$indexuser = $index;
break;
}
}
$calculedstartindex = $rohstartindex - $indexuser;
$calculedstartindex = $calculedstartindex >= 1 ? $calculedstartindex : $calculedstartindex + $maxstartindex;
$nrow = null;
if ($calculedstartindex !== count($entries)){
$nrow = null;
foreach ($entries as $entry) {
if ($entry['startIndex'] == $nsti) {
$nrow = $entry;
break;
}
}
}
if ($nrow) {
$nturnerin = [
'name' => $nrow['vorname'].' '.$nrow['name'].', '.$nrow['programm'],
'id' => $nrow['id']
];
} else {
$nturnerin = [
'name' => '--- nächste Gruppe ---',
'id' => 0
];
}
}
if ($isAdmin) {
echo json_encode([
'success' => true,
'id' => $editId,
'programm_id' => $programm_id,
'titel' => $titel,
'noten' => $noten
]);
} else {
echo json_encode([
'success' => true,
'id' => $editId,
'programm_id' => $programm_id,
'titel' => $titel,
'noten' => $noten,
'nturnerin' => $nturnerin
]);
}

View File

@@ -0,0 +1,327 @@
<?php
/*ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
// Show all errors except deprecation notices (these come from vendor libraries
// that aren't yet typed for newer PHP versions). Long-term fix: update
// dependencies to versions compatible with your PHP runtime.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);*/
// Start session if not already started
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
// Check access
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true ||
empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
// Validate POST input
if (!isset($_POST['abteilung'])) {
http_response_code(400);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$abteilung = trim($_POST['abteilung']);
$disciplines = db_select($mysqli, $tableGeraete, '*', '', [], 'start_index ASC');
// Load TCPDF
require $baseDir . '/wp-content/uploads/TCPDF-main/tcpdf.php';
$current_year = (date('n') > 6) ? date('Y') + 1 : date('Y');
class MYPDF extends TCPDF
{
public $current_year;
public $abteilung;
// Page header
public function Header()
{
$image_file = 'https://kutu-tage-beider-basel.testseite-fh-ht.ch/wp-content/uploads/2025/06/ktbb-logo.png';
$this->SetY(15);
$this->SetFont('helvetica', 'B', 20);
$this->Cell(0, 0, 'Protokoll Kutu-Tage beider Basel ' . $this->current_year . ' Abt. ' . $this->abteilung, 0, false, 'L', 0, '', 0, false, 'M', 'M');
$this->Image($image_file, 272, 5, 15, '', 'PNG', '', 'T', false, 300, '', false, false, 0, false, false, false);
}
// Page footer
public function Footer()
{
$this->SetY(-15);
$this->SetFont('helvetica', 'I', 8);
$this->Cell(0, 10, 'Seite ' . $this->getAliasNumPage() . ' von ' . $this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M');
}
}
$pdf = new MYPDF('L', 'mm', 'A4', true, 'UTF-8', false);
//$pdf->AddFont('outfit-bold', '', 'outfitb.php');
$pdf->current_year = $current_year;
$pdf->abteilung = $abteilung;
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Turnerinnen System');
$pdf->SetTitle("KTBB_Protokoll_Abt." . $abteilung . "_" . $current_year . ".pdf");
$pdf->SetMargins(10, 20, 10);
$pdf->SetAutoPageBreak(TRUE, 10);
$pdf->SetFont('helvetica', '', 9);
$startindex = 0;
foreach ($disciplines as $singledisciplin){
$startindex ++;
$name_kampfrichterin1 = 'Nicht eingetragen';
$name_kampfrichterin2 = 'Nicht eingetragen';
// Prepare SQL statement
$stmt = $mysqli->prepare("
SELECT * FROM $tableKrProtokoll
WHERE abteilung = ?
AND geraet = ?
");
$stmt->bind_param('ss', $abteilung, $singledisciplin['name']);
$stmt->execute();
$result = $stmt->get_result();
$krresults = $result->fetch_all(MYSQLI_ASSOC);
foreach ($krresults as $krresult){
if ($krresult['aufgabe'] == 1){
$name_kampfrichterin1 = $krresult['name'];
} elseif ($krresult['aufgabe'] == 2){
$name_kampfrichterin2 = $krresult['name'];
}
}
foreach ($disciplines as $shiftstartindex => $subdisciplin){
$pdf->AddPage();
$pdf->Ln(10);
$pdf->SetFont('', 'B', 14);
$pdf->Cell(0, 0, ucfirst($singledisciplin['name']), 0, 1, 'L');
$pdf->Ln(3);
$pdf->SetFont('', 'I', 9);
$newshiftindex = $shiftstartindex + 1;
$pdf->Cell(0, 0, 'Gruppe '. $newshiftindex , 0, 1, 'L');
$pdf->SetFont('', '');
$pdf->Ln(5);
$pdf->Cell(0, 0, '1. Kampfrichterin: ' . $name_kampfrichterin1, 0, 1, 'L');
$pdf->Ln(2);
$pdf->Cell(0, 0, '2. Kampfrichterin: ' . $name_kampfrichterin2, 0, 1, 'L');
$pdf->Ln(8);
$startg = $shiftstartindex - $startindex;
if ($startg < 1) {
$startg += 4; // shift into positive range
}
// Prepare SQL statement
$stmt = $mysqli->prepare("
SELECT
t.*,
agg.abteilung,
agg.geraete_index,
agg.start_index
FROM $tableTurnerinnen t
LEFT JOIN (
SELECT
ta.turnerin_id,
GROUP_CONCAT(DISTINCT a.name SEPARATOR ', ') AS abteilung,
GROUP_CONCAT(DISTINCT g.start_index SEPARATOR ', ') AS geraete_index,
ta.turnerin_index AS start_index
FROM $tableTurnerinnenAbt ta
INNER JOIN $tableAbt a
ON a.id = ta.abteilung_id
LEFT JOIN $tableGeraete g
ON g.id = ta.geraet_id
GROUP BY ta.turnerin_id
) agg ON agg.turnerin_id = t.id
WHERE (t.bezahlt = ? OR t.bezahltoverride = ?) AND agg.abteilung = ? AND agg.geraete_index = ?
ORDER BY agg.start_index DESC
");
$bezahlt1 = '2';
$bezahlt2 = '5';
$stmt->bind_param('ssss', $bezahlt1, $bezahlt2, $abteilung, $startg);
$stmt->execute();
$result = $stmt->get_result();
$entries = $result->fetch_all(MYSQLI_ASSOC);
if (!empty($entries)) {
$maxindex = $entries[0]['start_index'];
// Recalculate
foreach ($entries as &$singleorderentry) {
$singleorderentry['start_index'] -= $shiftstartindex;
if ($singleorderentry['start_index'] < 1) {
$singleorderentry['start_index'] += $maxindex;
}
}
unset($singleorderentry); // break the reference
// Reorder by recalculated startindex (ascending)
usort($entries, function($a, $b) {
return $a['start_index'] <=> $b['start_index'];
});
}
// Define columns (including discipline sub-columns)
$columns = [
'start_index' => ['header' => 'Str.'],
'name' => ['header' => 'Name'],
'vorname' => ['header' => 'Vorname'],
'programm' => ['header' => 'Programm'],
'geburtsdatum' => ['header' => 'Jg.'],
'verein' => ['header' => 'Verein'],
'e1 note '.strtolower($subdisciplin['name']) => ['header' => 'E1 Note '.ucfirst($subdisciplin['name'])],
'e2 note '.strtolower($subdisciplin['name']) => ['header' => 'E2 Note '.ucfirst($subdisciplin['name'])],
'e note '.strtolower($subdisciplin['name']) => ['header' => 'E Note '.ucfirst($subdisciplin['name'])],
'd-note '.strtolower($subdisciplin['name']) => ['header' => 'D Note '.ucfirst($subdisciplin['name'])],
'neutrale abzuege '.strtolower($subdisciplin['name']) => ['header' => 'N. Abzüge '.ucfirst($subdisciplin['name'])],
'note '.strtolower($subdisciplin['name']) => ['header' => 'Note '.ucfirst($subdisciplin['name'])],
];
// Initialize max widths with header widths (+4 mm padding)
foreach ($columns as $key => &$col) {
$col['max_width'] = $pdf->GetStringWidth($col['header']) + 4;
}
// Calculate max width of each column based on all data
foreach ($entries as $r) {
foreach ($columns as $key => &$col) {
isset($r[$key]) ? $r[$key] : '';
$text = '';
// Handle different column types
if ($key === 'start_index' && !empty($r['start_index'])) {
$text = (int)$r[$key];
} elseif ($key === 'geburtsdatum' && !empty($r['geburtsdatum'])) {
$text = (new DateTime($r['geburtsdatum']))->format('Y');
} elseif (strpos($key, 'd-note') === 0 && isset($r[$key]) && is_numeric($r[$key])) {
$text = number_format((float)$r[$key], 2, '.', ''); // 2 decimals
} elseif (isset($r[$key]) && is_numeric($r[$key])) {
$text = number_format((float)$r[$key], 3, '.', ''); // 3 decimals
} elseif (isset($r[$key])) {
$text = (string)$r[$key];
} else {
$text = '';
}
// Calculate width with padding
$w = $pdf->GetStringWidth($text) + 4;
// Update max width
if ($w > $col['max_width']) {
$col['max_width'] = $w;
}
}
}
unset($col);
$columns['geburtsdatum']['max_width'] = $pdf->GetStringWidth("0000") + 4;
// Print first header row
$pdf->SetFont('', 'B');
foreach ($columns as $key => $col) {
if (
$key === 'd-note' || // only column with dash
strpos($key, 'note') === 0 || // matches 'note...' at start
strpos($key, 'e note') === 0 || // matches 'e-note...'
strpos($key, 'e1 note') === 0 || // matches 'e1 note ...'
strpos($key, 'e2 note') === 0 || // matches 'e2 note ...'
strpos($key, 'neutrale abzuege') === 0 ||
$key === 'geburtsdatum' ||
$key === 'start_index'
) {
$align = 'C';
} else {
$align = 'L';
}
$pdf->Cell($col['max_width'], 7, $col['header'], 0, 0, $align);
}
// Move to next line after headers
$pdf->Ln();
$pdf->SetFont('', '');
foreach ($entries as $r) {
foreach ($columns as $key => $col) {
// Determine alignment
if (strpos($key, 'note') === 0 || strpos($key, 'e note') === 0 || strpos($key, 'd-note') === 0 || strpos($key, 'neutrale abzuege') === 0 || $key === 'start_index' || $key === 'geburtsdatum' || strpos($key, 'e1 note') === 0 || strpos($key, 'e2 note') === 0){
$align = 'C';
} else {
$align = 'L';
}
// Format the value based on type
if ($key === 'geburtsdatum' && !empty($r['geburtsdatum'])) {
$text = (new DateTime($r['geburtsdatum']))->format('Y');
} elseif (strpos($key, 'note') === 0 || strpos($key, 'e note') === 0 || strpos($key, 'd-note') === 0 || strpos($key, 'neutrale abzuege') === 0 || $key === 'gesamt' || strpos($key, 'e1 note') === 0 || strpos($key, 'e2 note') === 0){
$text = isset($r[$key]) ? number_format((float)$r[$key], 3) : '';
} else {
$text = isset($r[$key]) ? $r[$key] : '';
}
$pdf->Cell($col['max_width'], 6, $text, 1, 0, $align);
}
$pdf->Ln(); // Move to next row
}
$pdf->SetY(-50);
if ($name_kampfrichterin1 !== 'Nicht eingetragen' || $name_kampfrichterin2 !== 'Nicht eingetragen'){
$pdf->SetFont('', 'B');
$pdf->Cell(0, 28, 'Unterschrift:', 0, 1, 'L');
$pdf->SetFont('', '');
if ($name_kampfrichterin1 !== 'Nicht eingetragen'){
$pdf->Cell(120, 8, $name_kampfrichterin1.': ___________________________________________', 0, 0, 'L');
}
if ($name_kampfrichterin2 !== 'Nicht eingetragen'){
$pdf->Cell(90, 8, $name_kampfrichterin2.': ___________________________________________', 0, 0, 'L');
}
}
}
}
// Close statement
$stmt->close();
$pdf->Output("Protokoll_Kutu-Tage_beider_Basel_{$current_year}_Abt_{$abteilung}.pdf", 'D');
exit;

View File

@@ -0,0 +1,606 @@
<?php
use TCPDF;
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
// Show all errors except deprecation notices (these come from vendor libraries
// that aren't yet typed for newer PHP versions). Long-term fix: update
// dependencies to versions compatible with your PHP runtime.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
// Start session if not already started
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
// Check access
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true ||
empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
// Validate POST input
/*
if (!isset($_POST['prog']) && !isset($_POST['type'])) {
http_response_code(400);
exit;
}*/
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/db/db-functions.php';
$programm = trim($_POST['prog'] ?? 'p6a');
$buttontype = trim($_POST['type'] ?? 'export_programm');
$upperprogramm = strtoupper($programm);
$stmt = $mysqli->prepare("SELECT `id`, `name` FROM $tableGeraete ORDER BY start_index ASC");
if (!$stmt->execute()) {
http_response_code(400);
exit;
}
$result = $stmt->get_result();
$geraete = $result->fetch_all(MYSQLI_ASSOC);
$disciplines = array_map(
'strtolower',
array_column($geraete, 'name')
);
$stmt->close();
// Determine current year
$current_year = date('Y');
$monat = date('n');
if ($monat > 6) $current_year++;
// Prepare SQL statement
$stmt = $mysqli->prepare("
SELECT * FROM $tableTurnerinnen
WHERE LOWER(programm) = LOWER(?)
AND (bezahlt = ? OR bezahltoverride = ?)
ORDER BY rang ASC
");
$bezahlt1 = '2';
$bezahlt2 = '5';
$stmt->bind_param('sss', $programm, $bezahlt1, $bezahlt2);
$stmt->execute();
$result = $stmt->get_result();
$personen = $result->fetch_all(MYSQLI_ASSOC);
// Close statement
$stmt->close();
// 1. Get the IDs from the first query results
$turnerinnenIds = array_column($personen, 'id');
if (!empty($turnerinnenIds)) {
// 2. Create a string of placeholders: ?,?,?
$placeholders = implode(',', array_fill(0, count($turnerinnenIds), '?'));
// 3. Prepare the IN statement
$sqlNoten = "SELECT * FROM $tableNoten WHERE person_id IN ($placeholders) AND `jahr` = ?";
$stmtNoten = $mysqli->prepare($sqlNoten);
// --- FIX STARTS HERE ---
// 1. Combine all values into one flat array for binding
$paramsArray = array_merge($turnerinnenIds, [$current_year]);
// 2. Build the types string
// 'i' for every ID, plus 'i' (or 's') for the year
$types = str_repeat('i', count($turnerinnenIds)) . 's';
// 3. Unpack the combined array into the bind_param function
$stmtNoten->bind_param($types, ...$paramsArray);
// --- FIX ENDS HERE ---
$stmtNoten->execute();
$notenResult = $stmtNoten->get_result();
$notenEntries = $notenResult->fetch_all(MYSQLI_ASSOC);
$stmtNoten->close(); // Close inside the IF to avoid errors if IDs were empty
} else {
$notenEntries = [];
}
$rangNote = intval(db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rangNote']));
var_dump($rangNote);
$orderBestRang = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['orderBestRang']);
$okValuesOrderBestRang = ["ASC", "DESC"];
if (!in_array($orderBestRang, $okValuesOrderBestRang)) {
http_response_code(400);
exit;
}
$alleNoten = db_select($mysqli, $tableNotenBezeichnungen, "id, default_value, nullstellen, pro_geraet, geraete_json, zeige_auf_rangliste, name", "zeige_auf_rangliste = ? OR id = ?", ['1', $rangNote]);
$displayedNoten = [];
foreach ($alleNoten as $sN) {
if (intval($sN['zeige_auf_rangliste']) === 1) {
$displayedNoten[$sN['id']] = $sN;
}
}
$ascArrayDefaultValues = array_column($alleNoten, 'default_value', 'id');
$ascArrayGeraeteJSON = array_column($alleNoten, 'geraete_json', 'id');
foreach ($ascArrayGeraeteJSON as $key => $saagj) {
$ascArrayGeraeteJSON[$key] = json_decode($saagj, true) ?? [];
}
// 1. Initialize the structure for every person
$indexedNotenArray = [];
foreach ($personen as $sp) {
$pId = $sp['id'];
foreach ($geraete as $g) {
$indexedNotenArray[$pId][$g['id']] = [];
}
$indexedNotenArray[$pId][0] = []; // Total/Overall device per person
}
// 2. Fill with existing database values
$sortArray = [];
foreach ($notenEntries as $sn) {
$pId = $sn['person_id'];
$gId = $sn['geraet_id'];
$nId = $sn['note_bezeichnung_id'];
$val = $sn['value'];
$indexedNotenArray[$pId][$gId][$nId] = $val;
// Check if this specific note is the one we rank by
// Usually ranking happens on Device 0 (Total) for the $rangNote ID
if (intval($nId) === $rangNote && intval($gId) === 0) {
$sortArray[$pId] = $val; // FIXED: used = instead of ===
}
}
// Load TCPDF
require $baseDir . '/../composer/vendor/autoload.php';
// Optional: load custom font
$fontfile = $baseDir . '/wp-content/uploads/fonts/Inter-Regular.ttf'; // adjust path
if (file_exists($fontfile)) {
$fontname = TCPDF_FONTS::addTTFfont($fontfile, 'TrueTypeUnicode', '', 32);
}
class MYPDF extends TCPDF
{
public $current_year;
public $programm;
public $upperprogramm;
public $columns;
public $disciplines;
// Page header
public $headerBottomY = 0;
public function Header()
{
$image_file = 'https://kutu-tage-beider-basel.testseite-fh-ht.chhttps://kutu-tage-beider-basel.testseite-fh-ht.ch/wp-content/uploads/2025/06/ktbb-logo.png';
$this->SetY(15);
$this->SetFont('helvetica', 'B', 20);
$this->Cell(0, 0, 'Rangliste Kutu-Tage beider Basel ' . $this->current_year, 0, 1, 'L', 0, '', 0, false, 'M', 'M');
$preimageX = $this->GetX();
$preimageY = $this->GetY();
$this->Image($image_file, 272, 5, 15, '', 'JPG', '', 'T', false, 300, '', false, false, 0, false, false, false);
$this->SetX($preimageX);
$this->SetY($preimageY);
$this->SetFont('helvetica', '', 11);
$this->Cell(0, 10, 'Programm: ' . $this->upperprogramm, 0, 1, 'L');
$this->Ln(5);
$columns = $this->columns;
$disciplines = $this->disciplines;
// Print first header row
$preheaderX = $this->GetX();
$preheaderY = $this->GetY();
$this->SetFont('', 'B');
$this->Cell($columns['rang']['max_width'], 7, $columns['rang']['header'], 0, 0, 'C');
$this->Cell($columns['name']['max_width'], 7, $columns['name']['header'], 0, 0, 'L');
$this->Cell($columns['vorname']['max_width'], 7, $columns['vorname']['header'], 0, 0, 'L');
$this->Cell($columns['geburtsdatum']['max_width'], 7, $columns['geburtsdatum']['header'], 0, 0, 'C');
$this->Cell($columns['verein']['max_width'], 7, $columns['verein']['header'], 0, 0, 'L');
$startX = $this->GetX();
$startY = $this->GetY();
$this->SetLineWidth(0.2);
// Loop through disciplines for rotated headers
foreach ($disciplines as $d) {
$w = $columns["d-note $d"]['max_width'] + $columns["note $d"]['max_width'];
$ws = $columns["note $d"]['max_width'];
$x = $this->GetX();
$y = $this->GetY() + 7;
// Start transformation for rotation
$this->StartTransform();
// Rotate around top-left of cell
$this->Rotate(45, $x, $y);
// Draw a line **above the first data row**
$lineY = $startY + 7; // adjust 7 depending on cell height
$this->Line($x, $lineY, $x + $ws, $lineY);
// Print the rotated header text
$this->Cell($w, 7, ucfirst($d), 0, 0, 'L');
$this->StopTransform();
$this->SetX($x + $w);
}
$w = $columns["gesamt"]['max_width'];
$ws = $w;
$x = $this->GetX();
$y = $this->GetY() + 7;
// Start transformation for rotation
$this->StartTransform();
// Rotate around top-left of cell
$this->Rotate(45, $x, $y);
// Draw a line **above the first data row**
$lineY = $startY + 7; // adjust 7 depending on cell height
$this->SetLineWidth(0.6);
$this->Line($x, $lineY, $x + $ws, $lineY);
$this->SetLineWidth(0.2);
// Print the rotated header text
$this->Cell($w, 7, $columns['gesamt']['header'], 0, 0, 'L');
$this->StopTransform();
$this->SetX($x + $w);
$afterheaderX = $this->GetX();
$this->Ln();
$xheaderline = $preheaderX;
$yheaderline = $this->GetY();
$this->headerBottomY = $this->GetY();
}
// Page footer
public function Footer()
{
$this->SetY(-15);
$this->SetFont('helvetica', 'I', 8);
$this->Cell(0, 10, 'Seite ' . $this->getAliasNumPage() . ' von ' . $this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M');
$this->SetFont('', '');
$this->Cell(0, 10, $_SERVER['HTTP_HOST'], 0, 0, 'R', false, 'https://'.$_SERVER['HTTP_HOST'].'/ergebnis/'.$this->current_year, 0, false, 'T', 'M');
$this->SetLineWidth(0.6);
$this->Line(10, $this->headerBottomY, 297 - 10, $this->headerBottomY);
$this->SetLineWidth(0.2);
$this->SetY(0);
$this->SetX(5);
$this->SetFillColor(255, 255, 255); // white
$this->Cell(5, 190, '', 0, 0, 'L', true);
$this->SetY(0);
$this->SetX(297 - 10);
$this->Cell(5, 190, '', 0, 0, 'L', true);
}
}
$pdf = new MYPDF('L', 'mm', 'A4', true, 'UTF-8', false);
$pdf->current_year = $current_year;
$pdf->programm = $programm;
$pdf->upperprogramm = $upperprogramm;
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('WKVS-FH');
$pdf->SetTitle("KTBB_Ergebnisse_" . $programm . "_" . $current_year . ".pdf");
$pdf->SetAutoPageBreak(TRUE, 10);
$pdf->SetFont('helvetica', '', 11);
// Define columns (including discipline sub-columns)
$columns = [
'rang' => [ 0 => ['header' => 'Rang']],
'name' => [ 0 => ['header' => 'Name']],
'vorname' => [ 0 => ['header' => 'Vorname']],
'geburtsdatum' => [ 0 => ['header' => 'Jg.']],
'verein' => [ 0 => ['header' => 'Verein']],
];
foreach ($displayedNoten as $sdN) {
if (intval($sdN['pro_geraet']) === 1) {
foreach ($geraete as $g) {
$columns[$sdN['name']][$g['id']] = ['header' => $sdN['name'], 'nullstellen' => $sdN['nullstellen'] ?? 2];
}
} else {
$allowed = $ascArrayGeraeteJSON[$sdN['id']] ?? [];
foreach ($allowed as $gId) {
$columns[$sdN['name']][$gId] = ['header' => $sdN['name'], 'nullstellen' => $sdN['nullstellen'] ?? 2];
}
}
}
// Initialize max widths with header widths (+4 mm padding)
foreach ($columns as $key => $col) {
foreach ($col as $skey => $scol) {
$columns[$key][$skey]['max_width'] = $pdf->GetStringWidth($scol['header']) + 8;
}
}
// 3. Fill missing defaults and finalize the sortArray
foreach ($personen as $sp) {
$pId = $sp['id'];
// We check all possible devices (including 0)
foreach ($indexedNotenArray[$pId] as $sG => $currentNoten) {
foreach ($alleNoten as $noteDef) {
$neni = $noteDef['id'];
// Skip if note already exists for this person/device
if (isset($currentNoten[$neni])) continue;
// Logic for "Pro Gerät" vs "Specific/Total"
$isProGeraet = (intval($noteDef['pro_geraet']) === 1);
$allowedGeraete = $ascArrayGeraeteJSON[$neni] ?? [];
if ($isProGeraet) {
if ($sG === 0) continue;
} else {
if (!in_array($sG, $allowedGeraete)) continue;
}
// Assign default value
$defaultValue = $ascArrayDefaultValues[$neni] ?? 0;
$string = nuber_format($defaultValue, $noteDef['nullstellen']);
$indexedNotenArray[$pId][$sG][$neni] = $string;
$width = $pdf->GetStringWidth($string) + 4;
if ($w > $columns[$noteDef['name']][$sG]['max_width']) {
$columns[$noteDef['name']][$sG] = $w;
}
// If this missing note was our ranking note, add default to sortArray
if ($neni === $rangNote && $sG === 0) {
$sortArray[$pId] = $defaultValue;
}
}
}
}
function calculateRanks(array $scoreArray, $direction = 'DESC') {
// 1. Sort the scores while preserving keys
if ($direction === 'DESC') {
arsort($scoreArray); // High scores first
} else {
asort($scoreArray); // Low scores first
}
$ranks = [];
$currentRank = 0;
$lastScore = null;
$skipped = 0;
foreach ($scoreArray as $pId => $score) {
if ($score !== $lastScore) {
$currentRank += ($skipped + 1);
$skipped = 0;
} else {
$skipped++;
}
$ranks[$pId] = $currentRank;
$lastScore = $score;
}
return $ranks;
}
// 4. Calculate Ranks
// FIXED: Passing $orderBestRang (the string "ASC"/"DESC") instead of the array
$ranks = calculateRanks($sortArray, $orderBestRang);
// Calculate max width of each column based on all data
foreach ($personen as $p) {
foreach ($columns as $key => &$col) {
if (isset($p[$key])) {
$text = $p[$key];
} else {
$text = '';
}
$w = $pdf->GetStringWidth($text) + 4;
// Add some padding
if ($w > $col['max_width']) {
$col['max_width'] = $w;
}
}
}
unset($col);
$columns['geburtsdatum'][0]['max_width'] = $pdf->GetStringWidth("0000") + 8;
$tablew = 297 - 20; // total table width (A4 landscape in mm)
// Step 1: Calculate total width of fixed columns
$fixedWidth = 0;
/*
// Discipline columns (each discipline has two columns: "d-note" and "note")
foreach ($disciplines as $d) {
$fixedWidth += $columns["d-note $d"]['max_width'] + $columns["note $d"]['max_width'];
}
// Other fixed columns
$fixedColumns = ['geburtsdatum','rang','gesamt'];
foreach ($fixedColumns as $col) {
$fixedWidth += $columns[$col]['max_width'];
}
// Step 2: Compute extra space for flexible columns
$flexCols = ['name','vorname','verein']; // columns that can grow
$flexTotal = 0;
// Compute current total width of flexible columns
foreach ($flexCols as $col) {
$flexTotal += $columns[$col]['max_width'];
}
// Available width for flexible columns
$effTableWidth = $tablew - $fixedWidth;
$extraWidth = $effTableWidth - $flexTotal;
// Step 3: Distribute extra width proportionally among flexible columns
if ($extraWidth > 0) {
foreach ($flexCols as $col) {
$columns[$col]['max_width'] += ($columns[$col]['max_width'] / $flexTotal) * $extraWidth;
}
}
*/
$pdf->columns = $columns;
$pdf->disciplines = $disciplines;
$pdf->AddPage();
// After AddPage(), the header has been drawn
$margin_top = $pdf->headerBottomY;
// Now adjust your margins if needed
$pdf->SetMargins(10, $margin_top, 10); // +5 mm padding below header
$pdf->SetY($margin_top); // Move cursor below header manually
$mbs = false;
$mbl = false;
$pdf->SetFont('', '');
$index = 0;
foreach ($personen as $r) {
$pdf->SetTextColor(0, 0, 0);
$rang = $ranks[$r['id']];
if ($rang == 1) {
$pdf->SetFillColor(255, 235, 128);
} elseif($rang == 2) {
$pdf->SetFillColor(224, 224, 224);
} elseif($$rang == 3) {
$pdf->SetFillColor(230, 191, 153);
} elseif ($index % 2 == 0) {
$pdf->SetFillColor(255, 255, 255); // white
} else {
$pdf->SetFillColor(240, 240, 240); // light gray
}
$pdf->SetFont('', 'B');
/*
if ($buttontype === 'export_programm_bm') {
if (($r['verein'] === 'BTV Basel' || $r['verein'] === 'TV Basel') && $mbs === false){
$pdf->SetFillColor(0, 0, 0);
$pdf->SetTextColor(255, 255, 255);
$mbs = true;
} elseif (($r['verein'] === 'Kutu Regio Basel') && $mbl === false) {
$pdf->SetFillColor(255, 0, 0);
$pdf->SetTextColor(255, 255, 255);
$mbl = true;
}
}*/
$pdf->Cell($columns['rang'][0]['max_width'], 8, $rang, 'B', 0, 'C', true);
$pdf->SetFont('', '');
$pdf->Cell($columns['name'][0]['max_width'], 8, $r['name'], 'B', 0, 'L', true);
$pdf->Cell($columns['vorname'][0]['max_width'], 8, $r['vorname'], 'B', 0, 'L', true);
$pdf->Cell($columns['geburtsdatum'][0]['max_width'], 8, (new DateTime($r['geburtsdatum']))->format("Y"), 'B', 0, 'C', true);
$pdf->Cell($columns['verein'][0]['max_width'], 8, $r['verein'], 'B', 0, 'L', true);
foreach ($disciplines as $d) {
$d_note = isset($r["d-note $d"]) ?
number_format((float)$r["d-note $d"], 2) : '';
$note = isset($r["note $d"]) ? number_format((float)$r["note $d"], 3) : '';
$pdf->SetFont('', '', 9);
$pdf->Cell($columns["d-note $d"]['max_width'], 8, $d_note, 'LB', 0, 'C', true);
$pdf->SetFont('', '', 11);
$pdf->Cell($columns["note $d"]['max_width'], 8, $note, 'B', 0, 'C', true);
}
$gesamt = isset($r["gesamtpunktzahl"]) ? number_format((float)$r["gesamtpunktzahl"], 3) : '';
$pdf->SetFont('', 'B');
$pdf->Cell($columns['gesamt'][0]['max_width'], 8, $gesamt, 'B', 0, 'C', true);
$pdf->SetFont('', '');
$x = $pdf->GetX() - $columns['gesamt'][0]['max_width'];
$y = $pdf->GetY();
$pdf->SetLineWidth(0.6);
$pdf->Line($x, $y, $x, $y + 7.7);
$pdf->SetLineWidth(0.2);
$pdf->Ln();
$index++;
}
$pdf->SetFont('', '', 7);
$textanzturnerinnen = (count($entries) > 1) ? 'Turnerinnen': 'Turnerin';
$pdf->Cell(20, 6, count($entries).' '.$textanzturnerinnen, 0, 0, 'L');
if ($buttontype === 'export_programm' || $buttontype === 'export_programm_bm') {
$pdf->Output("KTBB_Ergebnisse_" . $programm . "_" . $current_year . ".pdf", 'D');
exit;
} elseif ($buttontype === 'upload_programm') {
$dir = $baseDir . '/wp-content/ergebnisse/';
if (!file_exists($dir)) mkdir($dir, 0755, true);
$localPath = $dir . "KTBB_Ergebnisse_" . $programm . "_" . $current_year . ".pdf";
if (file_exists($localPath)) unlink($localPath);
$pdf->Output($localPath, 'F');
$_SESSION['form_message'] = '<div class="success">PDF wurde hochgeladen</div>';
exit;
}

View File

@@ -0,0 +1,107 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
// Show all errors except deprecation notices (these come from vendor libraries
// that aren't yet typed for newer PHP versions). Long-term fix: update
// dependencies to versions compatible with your PHP runtime.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
// ---------- Get and sanitize input ----------
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$discipline = isset($_GET['discipline']) ? preg_replace('/[^a-zA-Z0-9 _-]/', '', $_GET['discipline']) : '';
if ($discipline !== 'boden') {
echo json_encode(['success' => false, 'message' => 'Invalid discipline']);
exit;
}
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
// ---------- Step 2: Get values from DB ----------
$result = $mysqli->query("SELECT t.bodenmusik, agg.filePath FROM `$tableTurnerinnen` t LEFT JOIN (SELECT a.id, a.file_path AS filePath FROM $tableAudiofiles a) agg ON agg.id = t.bodenmusik WHERE t.id = $id");
$row = $result->fetch_assoc();
if (!$row || !isset($row['bodenmusik'])) {
echo json_encode(['success' => false, 'message' => 'Row fetch failed '.$id]);
exit;
}
if ($row['bodenmusik'] === "0" || $row['filePath'] == null) {
echo json_encode(['success' => false, 'message' => 'Keine Musik']);
exit;
}
$folder = realpath($baseDir . '/displays/json');
if ($folder === false) {
echo json_encode([
'success' => false,
'message' => 'Could not find displays folder.'
]);
exit;
}
$filename = 'audio.json';
$filepath = $folder . '/' . $filename;
if (!is_writable($folder)) {
echo json_encode(['success' => false, 'message' => 'Folder not writable: ']);
exit;
}
if (!is_file($filepath)){
file_put_contents($filepath, []);
}
$jsonString = file_get_contents($filepath);
// decode JSON, fallback to empty array if invalid
$oldjson = json_decode($jsonString, true) ?? [];
$oldjson["musik"] = $row['filePath'];
$oldjson["start"] = true;
$jsonData = json_encode($oldjson);
// Write file
if (file_put_contents($filepath, $jsonData) === false) {
echo json_encode([
'success' => false,
'message' => 'Failed to write JSON file: ' . $filepath
]);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'JSON updated successfully for '.$discipline,
'disable_musik_button' => true
]);
exit;

View File

@@ -0,0 +1,57 @@
<?php
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$discipline = 'boden';
$folder = realpath($baseDir . '/displays/json');
if ($folder === false) {
echo json_encode([
'success' => false,
'message' => 'Could not find displays folder.'
]);
exit;
}
$filename = 'audio.json';
$filepath = $folder . '/' . $filename;
if (!is_writable($folder)) {
echo json_encode(['success' => false, 'message' => 'Folder not writable']);
exit;
}
if (!is_file($filepath)){
file_put_contents($filepath, []);
}
$jsonString = file_get_contents($filepath);
// decode JSON, fallback to empty array if invalid
$oldjson = json_decode($jsonString, true) ?? [];
$oldjson["start"] = false;
$jsonData = json_encode($oldjson);
// Write file
if (file_put_contents($filepath, $jsonData) === false) {
echo json_encode([
'success' => false,
'message' => 'Failed to write JSON file: ' . $filepath
]);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'JSON updated successfully for '.$discipline,
'disable_musik_button' => true
]);
exit;

View File

@@ -0,0 +1,114 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
session_start();
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$abteilung = isset($_POST['abteilung']) ? strval($_POST['abteilung']) : '1';
$aufgabe = isset($_POST['aufgabe']) ? strval($_POST['aufgabe']) : '2';
$name = isset($_POST['name']) ? strval($_POST['name']) : 'RK';
$geraet = isset($_POST['geraet']) ? strtolower($_POST['geraet']) : 'boden';
if ($abteilung === ''){
echo json_encode(['success' => false, 'message' => 'Keine Abteilung angegeben.']);
exit;
}
if ($aufgabe === ''){
echo json_encode(['success' => false, 'message' => 'Keine Aufgabe angegeben.']);
exit;
}
if (!is_numeric($aufgabe)){
echo json_encode(['success' => false, 'message' => 'Keine valide Aufgabe. (is not numeric)']);
exit;
}
if ($name === ''){
echo json_encode(['success' => false, 'message' => 'Kein Namen angegeben']);
exit;
}
$stmt = $mysqli->prepare("SELECT `name` FROM $tableGeraete ORDER BY start_index ASC");
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$result = $stmt->get_result();
$disciplines = array_map(
'strtolower',
array_column($result->fetch_all(MYSQLI_ASSOC), 'name')
);
$stmt->close();
if (!in_array($geraet, $disciplines)){
echo json_encode(['success' => false, 'message' => 'Invalides Gerät: '.$geraet]);
exit;
}
$stmt = $mysqli->prepare("SELECT * FROM $tableKrProtokoll WHERE abteilung = ? AND geraet = ? AND aufgabe = ? LIMIT 1");
$stmt->bind_param("sss", $abteilung, $geraet, $aufgabe);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
if ($row){
$updatestmt = $mysqli->prepare("UPDATE $tableKrProtokoll SET name = ? WHERE id = ?");
$updatestmt->bind_param("si", $name, $row['id']);
if (!$updatestmt->execute()) {
echo json_encode([
'success' => false,
'message' => 'Insert ERROR: ' . $updatestmt->error
]);
exit;
}
echo json_encode(['success' => true, 'message' => 'Updated: updated']);
exit;
} else {
$insertstmt = $mysqli->prepare("INSERT INTO $tableKrProtokoll (abteilung, geraet, name, aufgabe) VALUES (?, ?, ?, ?)");
$insertstmt->bind_param("ssss", $abteilung, $geraet, $name, $aufgabe);
if (!$insertstmt->execute()) {
echo json_encode([
'success' => false,
'message' => 'Insert ERROR: ' . $insertstmt->error
]);
exit;
}
echo json_encode(['success' => true, 'message' => 'Updated: inserted']);
exit;
}
?>

View File

@@ -0,0 +1,51 @@
<?php
session_start();
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$new_value = $_POST['freigabe'] ?? '';
$type = $_POST['type'] ?? 'nan';
$allowedTypes = ['kampfrichter', 'trainer'];
if (in_array($type, $allowedTypes)) {
$accessKey = "access_granted_" . $type;
$idKey = "passcode" . $type . "_id";
// 3. Check if they have access
$hasAccess = isset($_SESSION[$accessKey]) &&
$_SESSION[$accessKey] === true &&
!empty($_SESSION[$idKey]) &&
$_SESSION[$idKey] > 0;
if (!$hasAccess) {
echo json_encode(['success' => false, 'message' => 'no permissions']);
exit;
}
} else {
echo json_encode(['success' => false, 'message' => 'no permissions']);
exit;
}
if (!$new_value) {
echo json_encode('Invalid Input');
exit;
}
if ($type === 'kampfrichter'){
$_SESSION['selectedFreigabeKampfrichter'] = $new_value;
}
if ($type === 'trainer'){
$_SESSION['selectedFreigabeTrainer'] = $new_value;
}
// ---------- Return JSON ----------
echo json_encode(['success' => true, 'message' => 'SESSION updated']);
exit;

View File

@@ -0,0 +1,252 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
session_start();
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$person_id = isset($_POST['personId']) ? intval($_POST['personId']) : 0;
$field_type_id = intval($_POST['fieldTypeId'] ?? 0);
$gereat_id = intval($_POST['gereatId'] ?? 0);
$jahr = isset($_POST['jahr']) ? intval($_POST['jahr']) : 0;
$run_number = isset($_POST['run']) ? intval($_POST['run']) : 1;
if (!isset($_POST['value'])) {
echo json_encode(['success' => false, 'message' => 'Kein Value angegeben']);
exit;
}
$valueNoteUpdate = floatval($_POST['value']);
if ($person_id < 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Personen-ID']);
exit;
}
if ($jahr < 1) {
echo json_encode(['success' => false, 'message' => 'Invalides Jahr']);
exit;
}
if ($gereat_id < 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Geraet-ID']);
exit;
}
$geratExistiert = db_get_var($mysqli, "SELECT 1 FROM $tableGeraete WHERE id = ? LIMIT 1", [$gereat_id]);
if (!$geratExistiert) {
echo json_encode(['success' => false, 'message' => 'Invalide Geraet-ID']);
exit;
}
if ($field_type_id < 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Notentyp-ID']);
exit;
}
$noteConfig = db_select($mysqli, $tableNotenBezeichnungen, "*", "id = ?", [$field_type_id]);
if (count($noteConfig) !== 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Notentyp-ID']);
exit;
}
$singleNoteConfig = $noteConfig[0];
if ($singleNoteConfig['max_value'] !== null && $valueNoteUpdate > $singleNoteConfig['max_value']) {
echo json_encode(['success' => false, 'message' => "Wert zu hoch (max " . $singleNoteConfig['max_value'].")"]);
exit;
}
if ($singleNoteConfig['min_value'] !== null && $valueNoteUpdate < $singleNoteConfig['min_value']){
echo json_encode(['success' => false, 'message' => "Wert zu niedrig (min " . $singleNoteConfig['min_value'].")"]);
exit;
}
$sql = "INSERT INTO $tableNoten (`value`, `person_id`, `note_bezeichnung_id`, `geraet_id`, `jahr`, `run_number`)
VALUES (?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("siiiii", $valueNoteUpdate, $person_id, $field_type_id, $gereat_id, $jahr, $run_number);
$stmt->execute();
$stmt->close();
if ($singleNoteConfig['berechnung_json'] === null) {
echo json_encode(['success' => true, 'message' => "Wert aktualisiert"]);
exit;
}
require $baseDir . "/../scripts/string-calculator/string-calculator-functions.php";
$updateNoten = [];
$notenRechner = new NotenRechner();
try {
$abhaenigeRechnungen = json_decode($singleNoteConfig['berechnung_json']);
} catch (Exception $e) {
echo json_encode(['success' => true, 'message' => "Wert aktualisiert, fehler bei der Berechnung der weiteren Werte"]);
exit;
}
$geraete = db_select($mysqli, $tableGeraete, "id");
// Alle Werte werden von der Datenbank geholt und werden, wenn nicht vorhanden, durch den Standartwert ersetzt.
$alleNoten = db_select($mysqli, $tableNotenBezeichnungen, "id, berechnung, default_value, nullstellen, pro_geraet, geraete_json, anzahl_laeufe_json");
$noten = db_select($mysqli, $tableNoten, "`value`, `note_bezeichnung_id`, `geraet_id`, `run_number`", "`person_id` = ? AND `jahr` = ?", [$person_id, $jahr]);
$ascArrayDefaultValues = array_column($alleNoten, 'default_value', 'id');
$ascArrayProGeraet = array_column($alleNoten, 'pro_geraet', 'id');
$ascArrayGeraeteJSON = array_column($alleNoten, 'geraete_json', 'id');
$ascArrayAnzahlLaeufeJSON = array_column($alleNoten, 'anzahl_laeufe_json', 'id');
$ascArrayRechnungen = array_column($alleNoten, 'berechnung', 'id');
// $proGeraet = intval($calc['pro_geraet']) !== 1;
$indexedNotenArray = [];
foreach ($ascArrayGeraeteJSON as $key => $saagj) {
$ascArrayGeraeteJSON[$key] = json_decode($saagj, true);
}
foreach ($ascArrayAnzahlLaeufeJSON as $key => $saalj) {
$ascArrayAnzahlLaeufeJSON[$key] = json_decode($saalj, true) ?? [];
}
foreach ($geraete as $g) {
$indexedNotenArray[$g['id']] = [];
}
$indexedNotenArray[0] = [];
foreach ($noten as $sn) {
$indexedNotenArray[$sn['geraet_id']][$sn['note_bezeichnung_id']][$sn['run_number']] = $sn['value'];
}
$alleNotenIds = array_column($alleNoten, 'id') ?? [];
foreach ($indexedNotenArray as $sG => $siNA) {
$existierendeNotenIds = array_keys($siNA) ?? [];
$nichtExistierendeNotenIds = array_diff($alleNotenIds, $existierendeNotenIds) ?? [];
foreach ($nichtExistierendeNotenIds as $neni) {
if (!isset($ascArrayDefaultValues[$neni])) { continue; }
if (intval($ascArrayProGeraet[$neni]) === 1 && intval($sG) === 0) { continue; }
if (intval($ascArrayProGeraet[$neni]) !== 1 && (!is_array($ascArrayGeraeteJSON[$neni]) || !in_array($sG, $ascArrayGeraeteJSON[$neni]))) { continue; }
// For non-existent notes, we fill all runs with default value
// We set Run 1 by default, and if more are configured, also those
$indexedNotenArray[$sG][$neni][1] = $ascArrayDefaultValues[$neni];
// Check for more runs in config? (Actually, this might be overkill for defaults,
// but the calculator might need them)
}
}
// We only want to save the IDs that were actually recalculated
$idsToSave = [];
foreach ($abhaenigeRechnungen as $sRechnung) {
if ($sRechnung[1] !== "A" && intval($sRechnung[1]) !== $gereat_id) { continue; }
$rechnung = $ascArrayRechnungen[$sRechnung[0]] ?? null;
$gereadIdArrays = ($sRechnung[1] === "A") ? $gereat_id : $sRechnung[1];
$targetNoteId = $sRechnung[0];
$isProGeraet = (intval($ascArrayProGeraet[$targetNoteId]) === 1);
$allowedGeraete = $ascArrayGeraeteJSON[$targetNoteId] ?? [];
if ($isProGeraet) {
$gereadIdArrays = $gereat_id;
} elseif (in_array($gereat_id, $allowedGeraete)) {
$gereadIdArrays = $gereat_id;
} else {
$gereadIdArrays = 0;
}
if ($rechnung === null) {
echo json_encode(['success' => true, 'message' => "Wert aktualisiert, Fehler: Rechnung" . $sRechnung[0] . "nicht gefunden"]);
exit;
}
$calcResult = $notenRechner->berechneStringComplex($rechnung, $indexedNotenArray, $gereat_id);
if ($calcResult['success'] !== true) {
echo json_encode(['success' => true, 'message' => "Wert aktualisiert, Rechenfehler: " . ($calcResult['value'] ?? '')]);
exit;
}
// Update the local array (Always Run 1 for calculations for now, UNLESS we want calculated runs?)
// Most calculations are "Total" points which have run_number = 1
$indexedNotenArray[$gereadIdArrays][$sRechnung[0]][1] = $calcResult['value'];
// Track that this ID needs to be written to the database (Target run is 1)
$updatedValues[$gereadIdArrays][$sRechnung[0]][1] = $calcResult['value'];
}
// Prepare the statement once
$sql = "INSERT INTO $tableNoten (`value`, `person_id`, `note_bezeichnung_id`, `geraet_id`, `jahr`, `run_number`)
VALUES (?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)";
$stmt = $mysqli->prepare($sql);
$indexedNullstellen = array_column($alleNoten, 'nullstellen', 'id');
$formatedNoten = [];
foreach ($updatedValues as $gereat => $notenArray) {
foreach ($notenArray as $note => $runArray) {
foreach ($runArray as $run => $value) {
$stmt->bind_param("siiiii", $value, $person_id, $note, $gereat, $jahr, $run);
$stmt->execute();
$formatedNoten[$gereat][$note][$run] = number_format($value ,$indexedNullstellen[$note] ?? 2);
}
}
}
$formatedNoten[$gereat_id][$field_type_id][$run_number] = number_format($valueNoteUpdate ,$indexedNullstellen[$field_type_id] ?? 2);
$stmt->close();
$mysqli->close();
echo json_encode([
'success' => true,
'message' => "Wert aktualisiert, alle Berechnungen durchgeführt",
"noten" => $formatedNoten
]);

View File

@@ -0,0 +1,93 @@
<?php
session_start();
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1 || !isset($_SESSION['selectedFreigabeKampfrichter']) || $_SESSION['selectedFreigabeKampfrichter'] !== 'admin') {
http_response_code(403);
exit;
}
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
// ---------- Get and sanitize input ----------
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
$fieldType = isset($_POST['field_type']) ? preg_replace('/[^a-zA-Z0-9 _-]/', '', $_POST['field_type']) : '';
$discipline = isset($_POST['discipline']) ? preg_replace('/[^a-zA-Z0-9 _-]/', '', $_POST['discipline']) : '';
$value = isset($_POST['value']) ? floatval($_POST['value']) : 0;
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
if (!isset($value) || floatval($value) < 0 || !isset($discipline) || $discipline === ''|| !isset($fieldType) || $fieldType === '') {
http_response_code(422);
exit;
}
if ($discipline === 'all') {
$column = $fieldType;
} else {
$column = $fieldType . ' ' . $discipline;
}
$excluded_columns = [
'id',
'name',
'vorname',
'bezahlt',
'bezahltoverride',
'geburtsdatum',
'programm',
'verein',
'bodenmusik'
];
$sql = "SHOW COLUMNS FROM `$tableTurnerinnen`";
$result = $mysqli->query($sql);
$all_columns = [];
while ($row = $result->fetch_assoc()) {
$all_columns[] = $row['Field'];
}
$allowed_columns = array_values(
array_diff($all_columns, $excluded_columns)
);
if (!in_array($column, $allowed_columns, true)) {
http_response_code(422);
exit;
}
$stmt = $mysqli->prepare("UPDATE `$tableTurnerinnen` SET `$column` = ? WHERE id = ?");
$stmt->bind_param("di", $value, $id);
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$stmt->close();
$mysqli->close();
http_response_code(200);
echo json_encode([
'success' => true,
'message' => 'Updated successfully'
]);
exit;

View File

@@ -0,0 +1,216 @@
<?php
header('Content-Type: application/json');
session_start();
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
// ---------- Get and sanitize input ----------
$id = intval($_POST['personId']) ?? 0;
$geraetId = intval($_POST['geraetId']) ?? 0;
$jahr = isset($_POST['jahr']) ? preg_replace('/[^0-9]/', '', $_POST['jahr']) : '';
$anfrageType = $_POST['type'] ?? '';
$allowedTypes = ["neu", "start", "result"];
if (!in_array($anfrageType, $allowedTypes)) {
echo json_encode(['success' => false, 'message' => "Operation nicht gestattet."]);
exit;
}
if ($anfrageType !== "start" && ($id < 1 || intval($jahr) < 1)) {
echo json_encode(['success' => false, 'message' => 'Personen ID ist nicht valide.']);
exit;
}
if ($geraetId < 1) {
echo json_encode(['success' => false, 'message' => 'Invalid discipline']);
exit;
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$stmt = $mysqli->prepare("SELECT `name` FROM $tableGeraete WHERE `id` = ? LIMIT 1");
$stmt->bind_param("s", $geraetId);
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$result = $stmt->get_result();
if ($result->num_rows === 0) {
echo json_encode(['success' => false, 'message' => 'Invalid discipline']);
exit;
}
$geraetData = $result->fetch_assoc();
$geraetName = $geraetData['name'];
$stmt->close();
$folder = realpath($baseDir . '/displays/json');
if ($folder === false) {
echo json_encode([
'success' => false,
'message' => 'Could not find displays folder.'
]);
exit;
}
$filename = 'display_' . strtolower($geraetName) . '.json';
$filepath = $folder . '/' . $filename;
if (!is_writable($folder)) {
echo json_encode(['success' => false, 'message' => 'Folder not writable']);
exit;
}
$jsonString = file_get_contents($filepath);
// decode JSON, fallback to empty array if invalid
$oldjson = json_decode($jsonString, true) ?? [];
switch ($anfrageType) {
case "neu":
$stmt = $mysqli->prepare("SELECT * FROM `$tableTurnerinnen` WHERE id = ? LIMIT 1");
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);
if (!$rows || !is_array($rows) || count($rows) !== 1) {
echo json_encode(['success' => false, 'message' => 'Row fetch failed']);
exit;
}
$row = $rows[0];
// safely get value, default 0 if missing
$olduniqueid = $oldjson['uniqueid'] ?? 0;
$uniqueid = $olduniqueid + 1;
$data = ["noteLinks" => '',
"noteRechts" => '',
"id" => $id,
"name" => $row['name'],
"vorname" => $row['vorname'],
"programm" => $row['programm'],
"verein" => $row['verein'],
"start" => false,
"musik" => 'nan',
"uniqueid" => $uniqueid];
$jsonData = json_encode($data);
break;
case "start":
if (array_key_exists("start", $oldjson)) {
$oldjson["start"] = true;
$jsonData = json_encode($oldjson);
} else {
echo json_encode(['success' => false, 'message' => 'Turnerin nicht auf Display '.json_encode($oldjson).'; '.$jsonString]);
exit;
}
break;
case "result":
// 1. Get IDs and filter out empty values
$noteLinksId = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['displayIdNoteL']);
$noteRechtsId = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['displayIdNoteR']);
// Create an array of IDs that actually exist
$validIds = array_filter([$noteLinksId, $noteRechtsId]);
$noten = [];
$notenConfig = [];
if (!empty($validIds)) {
// 2. Fetch Noten (Only if we have IDs to look for)
$placeholders = implode(',', array_fill(0, count($validIds), '?'));
$sqlNoten = "SELECT `value`, `note_bezeichnung_id` FROM $tableNoten
WHERE person_id = ? AND `jahr` = ? AND `geraet_id` = ?
AND `note_bezeichnung_id` IN ($placeholders)";
$stmt = $mysqli->prepare($sqlNoten);
// Combine standard params with our dynamic ID list
$params = array_merge([$id, $jahr, $geraetId], $validIds);
$types = str_repeat('s', count($params));
$stmt->bind_param($types, ...$params);
$stmt->execute();
$notenDB = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
$noten = array_column($notenDB, 'value', 'note_bezeichnung_id');
$stmt->close();
// 3. Fetch Config
$sqlConfig = "SELECT `id`, `default_value`, `nullstellen`, `prefix_display`
FROM $tableNotenBezeichnungen WHERE `id` IN ($placeholders)";
$stmt = $mysqli->prepare($sqlConfig);
$typesConfig = str_repeat('s', count($validIds));
$stmt->bind_param($typesConfig, ...$validIds);
$stmt->execute();
$notenConfigDB = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
$notenConfig = array_column($notenConfigDB, null, 'id');
$stmt->close();
}
// 4. Helper function to safely format the output without crashing
$formatNote = function($id) use ($noten, $notenConfig) {
if (!$id || !isset($notenConfig[$id])) {
return ""; // Return empty string if ID is not set or not found in DB
}
$conf = $notenConfig[$id];
$val = $noten[$id] ?? $conf['default_value'] ?? 0;
$prec = $conf['nullstellen'] ?? 2;
$pre = $conf['prefix_display'] ?? '';
return $pre . number_format((float)$val, (int)$prec, '.', '');
};
// 5. Assign to JSON
$oldjson["noteLinks"] = $formatNote($noteLinksId);
$oldjson["noteRechts"] = $formatNote($noteRechtsId);
$jsonData = json_encode($oldjson);
break;
}
// Write file
if (file_put_contents($filepath, $jsonData) === false) {
echo json_encode([
'success' => false,
'message' => 'Failed to write JSON file'
]);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'JSON updated successfully for ' . $geraetName,
'data' => json_decode($jsonData, true),
'nameGeraet' => strtolower($geraetName)
]);
exit;

View File

@@ -0,0 +1,115 @@
<?php
header('Content-Type: application/json');
session_start();
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
// ---------- Get and sanitize input ----------
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
$discipline = isset($_POST['discipline']) ? preg_replace('/[^a-zA-Z0-9 _-]/', '', $_POST['discipline']) : '';
$stmt = $mysqli->prepare("SELECT `name` FROM $tableGeraete ORDER BY start_index ASC");
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$result = $stmt->get_result();
$allowed_disciplines = array_map(
'strtolower',
array_column($result->fetch_all(MYSQLI_ASSOC), 'name')
);
$stmt->close();
if (!in_array($discipline, $allowed_disciplines)) {
echo json_encode(['success' => false, 'message' => 'Invalid discipline']);
exit;
}
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
// ---------- Step 2: Get values from DB ----------
$result = $mysqli->query("SELECT * FROM `$tableTurnerinnen` WHERE id = $id");
$row = $result->fetch_assoc();
if (!$row) {
echo json_encode(['success' => false, 'message' => 'Row fetch failed']);
exit;
}
$folder = realpath($baseDir . '/displays/json');
if ($folder === false) {
echo json_encode([
'success' => false,
'message' => 'Could not find displays folder.'
]);
exit;
}
$filename = 'display_' . $discipline . '.json';
$filepath = $folder . '/' . $filename;
if (!is_writable($folder)) {
echo json_encode(['success' => false, 'message' => 'Folder not writable: ' . $folder]);
exit;
}
$jsonString = file_get_contents($filepath);
// decode JSON, fallback to empty array if invalid
$oldjson = json_decode($jsonString, true) ?? [];
if (array_key_exists("note", $oldjson) && array_key_exists("dnote", $oldjson)) {
$oldjson["note"] = (float)$row['note '.$discipline];
$oldjson["dnote"] = (float)$row['d-note '.$discipline];
} else {
echo json_encode([
'success' => false,
'message' => 'ERROR: JSON keys "note" or "dnote" do not exist'
]);
exit;
}
$jsonData = json_encode($oldjson);
// Write file
if (file_put_contents($filepath, $jsonData) === false) {
echo json_encode([
'success' => false,
'message' => 'Failed to write JSON file: ' . $filepath
]);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'JSON updated successfully for '.$discipline,
]);
exit;

View File

@@ -0,0 +1,97 @@
<?php
header('Content-Type: application/json');
session_start();
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
// ---------- Get and sanitize input ----------
$discipline = isset($_GET['discipline']) ? preg_replace('/[^a-zA-Z0-9 _-]/', '', $_GET['discipline']) : '';
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$stmt = $mysqli->prepare("SELECT `name` FROM $tableGeraete ORDER BY start_index ASC");
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$result = $stmt->get_result();
$allowed_disciplines = array_map(
'strtolower',
array_column($result->fetch_all(MYSQLI_ASSOC), 'name')
);
$stmt->close();
if (!in_array($discipline, $allowed_disciplines)) {
echo json_encode(['success' => false, 'message' => 'Invalid discipline']);
exit;
}
$folder = realpath($baseDir . '/displays/json');
if ($folder === false) {
echo json_encode([
'success' => false,
'message' => 'Could not find displays folder.'
]);
exit;
}
$filename = 'display_' . $discipline . '.json';
$filepath = $folder . '/' . $filename;
if (!is_writable($folder)) {
echo json_encode(['success' => false, 'message' => 'Folder not writable']);
exit;
}
$jsonString = file_get_contents($filepath);
// decode JSON, fallback to empty array if invalid
$oldjson = json_decode($jsonString, true) ?? [];
if (array_key_exists("start", $oldjson)) {
$oldjson["start"] = true;
$jsonData = json_encode($oldjson);
} else {
echo json_encode(['success' => false, 'message' => 'Turnerin nicht auf Display '.json_encode($oldjson).'; '.$jsonString]);
exit;
}
// Write file
if (file_put_contents($filepath, $jsonData) === false) {
echo json_encode([
'success' => false,
'message' => 'Failed to write JSON file'
]);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'JSON updated successfully for '.$discipline,
'disable_start_button' => true
]);
exit;

View File

@@ -0,0 +1,122 @@
<?php
header('Content-Type: application/json');
session_start();
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
// ---------- Get and sanitize input ----------
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$discipline = isset($_GET['discipline']) ? preg_replace('/[^a-zA-Z0-9 _-]/', '', $_GET['discipline']) : '';
$stmt = $mysqli->prepare("SELECT `name` FROM $tableGeraete ORDER BY start_index ASC");
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$result = $stmt->get_result();
$allowed_disciplines = array_map(
'strtolower',
array_column($result->fetch_all(MYSQLI_ASSOC), 'name')
);
$stmt->close();
if (!in_array($discipline, $allowed_disciplines)) {
echo json_encode(['success' => false, 'message' => 'Invalid discipline']);
exit;
}
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
// ---------- Step 2: Get values from DB ----------
$result = $mysqli->query("SELECT name, vorname, verein, programm FROM `$tableTurnerinnen` WHERE id = $id");
$row = $result->fetch_assoc();
if (!$row) {
echo json_encode(['success' => false, 'message' => 'Row fetch failed']);
exit;
}
$folder = realpath($baseDir . '/displays/json');
if ($folder === false) {
echo json_encode([
'success' => false,
'message' => 'Could not find displays folder. Tried: ' . __DIR__ . '/../displays'
]);
exit;
}
$filename = 'display_' . $discipline . '.json';
$filepath = $folder . '/' . $filename;
if (!is_writable($folder)) {
echo json_encode(['success' => false, 'message' => 'Folder not writable: ' . $folder]);
exit;
}
if (file_put_contents($filepath, $jsonData) === false) {
echo json_encode(['success' => false, 'message' => 'Failed to write file: ' . $filepath]);
exit;
}
$jsonString = file_get_contents($folder . $filename);
// decode JSON, fallback to empty array if invalid
$oldjson = json_decode($jsonString, true) ?? [];
// safely get value, default 0 if missing
$olduniqueid = $oldjson['uniqueid'] ?? 0;
$uniqueid = $olduniqueid + 1;
$data = ["note" => 'nan',
"dnote" => 'nan',
"id" => $id,
"name" => $row['name'],
"vorname" => $row['vorname'],
"programm" => $row['programm'],
"verein" => $row['verein'],
"start" => false,
"musik" => 'nan',
"uniqueid" => $uniqueid];
$jsonData = json_encode($data);
// Encode JSON with readable formatting
$jsonData = json_encode($data);
// Write file
if (file_put_contents($filepath, $jsonData) === false) {
echo json_encode([
'success' => false,
'message' => 'Failed to write JSON file: ' . $filepath
]);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'JSON updated successfully for '.$discipline,
'disable_turnerin_button' => true,
'enable_result_button' => true
]);
exit;

View File

@@ -0,0 +1,160 @@
<?php
session_start();
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
//ini_set('display_errors', 1);
//ini_set('display_startup_errors', 1);
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$noten = db_select($mysqli, $tableNotenBezeichnungen, "id, berechnung, type");
// 1. Re-index the array so the keys match the database IDs
$notenById = array_column($noten, null, 'id');
$berechnungen = [];
foreach ($notenById as $id => $sn) {
if ($sn['type'] === 'berechnung') {
$berechnungen[] = $sn;
}
}
if (empty($berechnungen)) {
echo json_encode(['success' => true, 'message' => "Keine Berechnungen ausgewählt"]);
exit;
}
require $baseDir . "/../scripts/string-calculator/string-calculator-functions.php";
$notenRechner = new NotenRechner();
// 1. Build the direct map
// Format: [ Changed_Note_ID => [ "CalcId|GeraetId" => [CalcId, GeraetId] ] ]
$dependencyMap = [];
foreach ($berechnungen as $calc) {
$neededIdsArray = $notenRechner->getBenoetigteIdsComplex($calc['berechnung']);
if (empty($neededIdsArray)) {
continue;
}
$calcId = (int)$calc['id'];
foreach ($neededIdsArray as $needed) {
$nId = (int)$needed['noteId'];
// Keep geraetId as integer if it's a number (e.g., 3), otherwise string ('S')
$gId = is_numeric($needed['geraetId']) ? (int)$needed['geraetId'] : $needed['geraetId'];
// Create a unique string key so we don't store exact duplicates
$nodeKey = $calcId . '|' . $gId;
if (!isset($dependencyMap[$nId])) {
$dependencyMap[$nId] = [];
}
// Store it as the "little array" you requested: [DependentCalcId, GeraetId]
$dependencyMap[$nId][$nodeKey] = [$calcId, $gId];
}
}
// 2. Our recursive helper function (Updated for complex nodes)
function getCompleteDependencyChain($id, $directMap, $visited = [])
{
// If this ID doesn't have anything depending on it, return empty
if (!isset($directMap[$id])) {
return [];
}
$allDependencies = [];
foreach ($directMap[$id] as $nodeKey => $complexNode) {
// CIRCULAR DEPENDENCY CHECK:
// We check against the string key (e.g., "10|S") to prevent infinite loops
if (isset($visited[$nodeKey])) {
continue;
}
// 1. Mark this specific node as visited
$visited[$nodeKey] = true;
// 2. Add the little array [CalcId, GeraetId] to our master list
$allDependencies[$nodeKey] = $complexNode;
// 3. Recursively find everything that depends on THIS calculation ID
// $complexNode[0] is the dependent Calc ID
$childDependencies = getCompleteDependencyChain($complexNode[0], $directMap, $visited);
// 4. Merge the child results into our master list safely
foreach ($childDependencies as $childKey => $childNode) {
$allDependencies[$childKey] = $childNode;
$visited[$childKey] = true; // Ensure the parent loop knows this was visited
}
}
return $allDependencies;
}
// 3. Create the final flattened map for ALL IDs
$flatDependencyMap = [];
foreach (array_keys($notenById) as $id) {
$chain = getCompleteDependencyChain($id, $dependencyMap);
// Only add it if dependencies exist
if (!empty($chain)) {
// array_values() removes the "10|S" string keys, turning it into a perfect
// 0-indexed array for clean JSON encoding: [[10, "S"], [12, 3]]
$flatDependencyMap[$id] = array_values($chain);
}
}
// 4. Database Updates
// Step 1: Reset all rows to NULL in a single query
$resetSql = "UPDATE $tableNotenBezeichnungen SET `berechnung_json` = NULL";
$mysqli->query($resetSql);
// Step 2: Prepare the statement
$updateSql = "UPDATE $tableNotenBezeichnungen SET `berechnung_json` = ? WHERE id = ?";
$stmt = $mysqli->prepare($updateSql);
foreach ($flatDependencyMap as $id => $completeDependencyArray) {
if (empty($completeDependencyArray)) {
continue;
}
$jsonString = json_encode($completeDependencyArray);
// Bind parameters: 's' for string (JSON), 'i' for integer (ID)
$stmt->bind_param("si", $jsonString, $id);
$stmt->execute();
}
$stmt->close();
echo json_encode(['success' => true, 'message' => "Abhaengigkeiten berechnet"]);
exit;

View File

@@ -0,0 +1,201 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
session_start();
if (empty($_SESSION['access_granted_kampfrichter']) || $_SESSION['access_granted_kampfrichter'] !== true || empty($_SESSION['passcodekampfrichter_id']) || $_SESSION['passcodekampfrichter_id'] < 1) {
http_response_code(403);
exit;
}
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'kr';
$data = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$person_id = isset($_POST['personId']) ? intval($_POST['personId']) : 0;
$field_type_id = intval($_POST['fieldTypeId'] ?? 0);
$gereat_id = intval($_POST['gereatId'] ?? 0);
$jahr = isset($_POST['jahr']) ? intval($_POST['jahr']) : 0;
if (!isset($_POST['value'])) {
echo json_encode(['success' => false, 'message' => 'Kein Value angegeben']);
exit;
}
$value = floatval($_POST['value']);
if ($person_id < 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Personen-ID']);
exit;
}
if ($jahr < 1) {
echo json_encode(['success' => false, 'message' => 'Invalides Jahr']);
exit;
}
if ($gereat_id < 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Geraet-ID']);
exit;
}
$geratExistiert = db_get_var($mysqli, "SELECT 1 FROM $tableNotenBezeichnungen WHERE id = ? LIMIT 1", [$gereat_id]);
if (!$geratExistiert) {
echo json_encode(['success' => false, 'message' => 'Invalide Geraet-ID']);
exit;
}
if ($field_type_id < 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Notentyp-ID']);
exit;
}
$noteConfig = db_select($mysqli, $tableNotenBezeichnungen, "*", "id = ?", [$field_type_id]);
if (count($noteConfig) !== 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Notentyp-ID']);
exit;
}
$singleNoteConfig = $noteConfig[0];
if ($singleNoteConfig['max_value'] !== null && $value > $singleNoteConfig['max_value']) {
echo json_encode(['success' => false, 'message' => "Wert zu hoch (max " . $singleNoteConfig['max_value'].")"]);
exit;
}
if ($singleNoteConfig['min_value'] !== null && $value < $singleNoteConfig['min_value']){
echo json_encode(['success' => false, 'message' => "Wert zu niedrig (min " . $singleNoteConfig['min_value'].")"]);
exit;
}
$sql = "INSERT INTO $tableNoten (`value`, `person_id`, `note_bezeichnung_id`, `geraet_id`, `jahr`)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("siiii", $value, $person_id, $field_type_id, $gereat_id, $jahr);
$stmt->execute();
$stmt->close();
if ($singleNoteConfig['berechnung_json'] === null) {
echo json_encode(['success' => true, 'message' => "Wert aktualisiert"]);
exit;
}
require $baseDir . "/../scripts/string-calculator/string-calculator-functions.php";
$updateNoten = [];
$notenRechner = new NotenRechner();
try {
$abhaenigeRechnungen = json_decode($singleNoteConfig['berechnung_json']);
} catch (Exception $e) {
echo json_encode(['success' => true, 'message' => "Wert aktualisiert, fehler bei der Berechnung der weiteren Werte"]);
exit;
}
// Alle Werte werden von der Datenbank geholt und werden, wenn nicht vorhanden, durch den Standartwert ersetzt.
$alleNoten = db_select($mysqli, $tableNotenBezeichnungen, "id, berechnung, default_value, nullstellen");
$noten = db_select($mysqli, $tableNoten, "`value`, `note_bezeichnung_id`", "`person_id` = ? AND `geraet_id` = ? AND `jahr` = ?", [$person_id, $gereat_id, $jahr]);
$ascArrayDefaultValues = array_column($alleNoten, 'default_value', 'id');
$ascArrayRechnungen = array_column($alleNoten, 'berechnung', 'id');
$existierendeNotenIds = array_column($noten, 'note_bezeichnung_id') ?? [];
$alleNotenIds = array_column($alleNoten, 'id') ?? [];
$nichtExistierendeNotenIds = array_diff($alleNotenIds, $existierendeNotenIds) ?? [];
$noten = array_column($noten, 'value', 'note_bezeichnung_id');
foreach ($nichtExistierendeNotenIds as $neni) {
if (!isset($ascArrayDefaultValues[$neni])) { continue; }
$noten[$neni] = $ascArrayDefaultValues[$neni];
}
// We only want to save the IDs that were actually recalculated
$idsToSave = [];
foreach ($abhaenigeRechnungen as $sRechnung) {
$rechnung = $ascArrayRechnungen[$sRechnung] ?? null;
if ($rechnung === null) {
echo json_encode(['success' => true, 'message' => "Wert aktualisiert, Fehler: Rechnung $sRechnung nicht gefunden"]);
exit;
}
$calcResult = $notenRechner->berechneString($rechnung, $noten);
if ($calcResult['success'] !== true) {
echo json_encode(['success' => true, 'message' => "Wert aktualisiert, Rechenfehler: " . ($calcResult['value'] ?? '')]);
exit;
}
// Update the local array so the NEXT calculation in the loop can use this new value
$noten[$sRechnung] = $calcResult['value'];
// Track that this ID needs to be written to the database
$idsToSave[] = $sRechnung;
}
// Prepare the statement once
$sql = "INSERT INTO $tableNoten (`value`, `person_id`, `note_bezeichnung_id`, `geraet_id`, `jahr`)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)";
$stmt = $mysqli->prepare($sql);
foreach ($idsToSave as $notenId) {
$currentValue = $noten[$notenId]; // Get the calculated value from our array
// i = integer, s = string (use 's' for decimals/floats to prevent rounding issues in PHP)
$stmt->bind_param("siiii", $currentValue, $person_id, $notenId, $gereat_id, $jahr);
$stmt->execute();
}
$stmt->close();
$mysqli->close();
// 1. Combine the ID the user sent with the IDs we recalculated
$changedIds = array_merge([$field_type_id], $idsToSave);
// 2. Filter the $noten array to only include these keys
// array_flip turns [10, 20] into [10 => 0, 20 => 1] so we can intersect by keys
$changedNoten = array_intersect_key($noten, array_flip($changedIds));
$indexedNullstellen = array_column($alleNoten, 'nullstellen', 'id');
foreach ($changedNoten as $key => $scN) {
$changedNoten[$key] = number_format($scN ,$indexedNullstellen[$key] ?? 2);
}
echo json_encode([
'success' => true,
'message' => "Wert aktualisiert, alle Berechnungen durchgeführt",
"noten" => $changedNoten
]);

View File

@@ -0,0 +1,192 @@
jQuery(document).ready(function($) {
$('.ranglisteExport').on('click', function() {
const $button = $(this);
const progId = $button.data('id');
const fieldType = $button.data('field_type');
// Visual feedback (optional but recommended)
$button.prop('disabled', true).text('Generating...');
const url = '/intern/scripts/kampfrichter/ajax/ajax-neu_rangliste.php';
fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
prog: progId,
type: fieldType
})
})
.then(response => {
// CRITICAL: Check if the server actually returned a success code
if (!response.ok) {
throw new Error('Server returned an error (Status ' + response.status + ')');
}
return response.blob();
})
.then(blob => {
if (fieldType !== 'upload_programm') {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `Ergebnisse_${progId}.pdf`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
} else {
alert('PDF auf Webseite geladen!');
}
})
.catch(error => {
console.error('Export Error:', error);
alert('Fehler beim Exportieren der Rangliste.');
})
.finally(() => {
// Restore button state
$button.prop('disabled', false).text('Export PDF');
});
});
$('.protokollExport').on('click', function() {
console.log('ok');
const $input = $(this);
// Build the data to send
const data = new URLSearchParams();
data.append('abteilung', $input.data('abteilung'));
// Record start time
const start = performance.now();
const url = '/intern/scripts/kampfrichter/ajax/ajax-neu_protokoll.php';
fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
abteilung: $input.data('abteilung')
})
})
.then(res => res.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = "KTBB_Protokoll.pdf"; // optional
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
});
});
let activeEdit = null;
console.log('pre');
$(document).on('click', '.editableValue', function () {
console.log('ok');
const input = $(this);
// Already editing
if (!input.prop('readonly')) {
return;
}
// Close another active edit
if (activeEdit && activeEdit.get(0) !== input.get(0)) {
cancelEdit(activeEdit);
}
input.data('original', input.val());
input.prop('readonly', false).focus().select();
activeEdit = input;
input.on('keydown.edit', function (e) {
if (e.key === 'Enter') {
e.preventDefault();
saveEdit(input);
}
if (e.key === 'Escape') {
e.preventDefault();
cancelEdit(input);
}
});
input.on('blur.edit', function () {
saveEdit(input);
});
});
function saveEdit(input) {
const originalValue = input.data('original');
const newValue = input.val();
const type = input.data('type');
const discipline = input.data('discipline');
const dataId = input.data('id');
if (newValue === originalValue) {
input.prop('readonly', true);
cleanup(input);
return;
}
input.addClass('is-saving');
$.ajax({
url: '/intern/scripts/kampfrichter/ajax/ajax-update_value_kampfrichter_admin.php',
method: 'POST',
data: {
id: dataId,
field_type: type,
discipline: discipline,
value: newValue
},
success: function () {
input.prop('readonly', true);
const row = input.closest('td');
if (row.length) {
row.css(
'background',
'radial-gradient(circle at bottom right, #22c55e, transparent 55%)'
);
setTimeout(() => row.css('background', ''), 2000);
}
ws.send(JSON.stringify({
type: "KAMPFRICHTER_UPDATE",
payload: {
discipline: discipline,
id: dataId,
val: newValue
}
}));
},
error: function () {
input.val(originalValue).prop('readonly', true);
alert('Speichern fehlgeschlagen');
},
complete: function () {
input.removeClass('is-saving');
cleanup(input);
}
});
}
function cancelEdit(input) {
input.val(input.data('original')).prop('readonly', true);
cleanup(input);
}
function cleanup(input) {
input.off('.edit');
activeEdit = null;
}
});

View File

@@ -0,0 +1,876 @@
document.addEventListener('keydown', function (e) {
// Mac = Option, Windows/Linux = Alt
const isOptionOrAlt = e.altKey || e.metaKey;
if (isOptionOrAlt && e.shiftKey && e.key.toLowerCase() === 'f') {
toggleFullscreen();
}
});
function toggleFullscreen() {
// If not in fullscreen → enter fullscreen
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen()
.catch(err => console.error("Fullscreen error:", err));
}
// If already fullscreen → exit fullscreen
else {
document.exitFullscreen();
}
}
let messagePosArray = [];
function displayMsg(type, msg) {
const colors = ["#900000ff", "#00b200ff"];
if (type !== 0 && type !== 1) return;
// idx is ALWAYS a valid non-negative index now
const $div = $('<div class="msgBox"></div>')
.css({'border-color': colors[type]})
.text(msg);
$('.msgDiv').append($div);
// trigger entry animation
setTimeout(() => {
$div.addClass('show');
}, 200);
setTimeout(() => {
// First: set the transition properties
$div.css({
'transition': 'all 0.3s ease'
});
// Next frame: apply the transform so the transition animates
requestAnimationFrame(() => {
$div.removeClass('show');
$div.css({
'transform': 'scaleY(0) translateX(calc(100% + 40px))'
});
});
}, 3000);
// auto-remove
setTimeout(() => {
$div.remove();
}, 3500);
}
const text = document.getElementById('wsInfo');
const rect = document.getElementById('wsInfoRectangle');
let ws;
let firstConnect = true;
const RETRY_DELAY = 2000; // ms
const urlAjaxNewWSToken = '/intern/scripts/ajax-create-ws-token.php';
async function fetchNewWSToken(freigabe) {
try {
const response = await fetch(urlAjaxNewWSToken, {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({ access: freigabe })
});
if (!response.ok) return null;
const data = await response.json();
return data.success ? data.token : null;
} catch (error) {
console.error("Token fetch failed:", error);
return null;
}
}
async function startWebSocket() {
console.log("Attempting WebSocket connection...");
let token;
if (firstConnect) {
token = window.WS_ACCESS_TOKEN;
} else {
token = await fetchNewWSToken('kampfrichter');
}
if (!token) {
console.error("No valid token available. Retrying...");
scheduleRetry();
return;
}
try {
ws = new WebSocket(`wss://${window.location.hostname}/ws/?access=token&token=${token}`);
} catch (err) {
console.error("Malformed WebSocket URL", err);
scheduleRetry();
return;
}
ws.onopen = () => {
console.log("WebSocket connected!");
if (!firstConnect) {
displayMsg(1, "Live Syncronisation wieder verfügbar");
}
firstConnect = true;
rect.innerHTML =
'<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="#28a745"></circle><path d="M7 12l3 3 7-7" stroke="white" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
requestAnimationFrame(() => {
text.style.opacity = 1;
});
};
ws.onerror = (event) => {
console.error("WebSocket error observed." + JSON.stringify(event));
};
ws.onclose = (event) => {
displayMsg(0, "Live Syncronisation verloren");
firstConnect = false;
rect.innerHTML =
'<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="#dc3545"/><path d="M8 8l8 8M16 8l-8 8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
requestAnimationFrame(() => {
text.style.opacity = 1;
});
scheduleRetry();
};
}
function scheduleRetry() {
console.log(`Retrying in ${RETRY_DELAY}ms...`);
setTimeout(startWebSocket, RETRY_DELAY);
}
// Start the initial connection attempt safely
startWebSocket();
$.fn.updateCurrentEdit = function() {
return this.each(function() {
const $input = $(this);
const url = '/intern/scripts/kampfrichter/ajax/ajax-kampfrichter_currentedit.php';
if ($input.attr('data-person-id') === "0"){
$('<form>', {
action: '/intern/kampfrichter',
method: 'post'
})
.append($('<input>', {
type: 'hidden',
name: 'next_subabt',
value: 1
}))
.append($('<input>', {
type: 'hidden',
name: 'next_subabt_submit',
value: '>'
}))
.appendTo('body')
.submit();
}
fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
csrf_token: window.CSDR_TOKEN,
editId: $input.attr('data-person-id'),
geraet: $input.attr('data-geraet-id') ?? null
})
})
.then(res => res.json())
.then(response => {
if (response.success) {
$(".current-turnerin-name").css({
'color': '#209200ff',
'transition': 'all 0.3s ease-out'
});
setTimeout(() => $(".current-turnerin-name").css({
'color': ''
}), 2000);
$(".div_edit_values_user").css("display", "flex");
$(".current-turnerin-name").text(response.titel);
$(".fv_nextturnerin").text(response.nturnerin?.name ?? '');
$(".fv_nextturnerin").val(response.nturnerin?.id ?? 0).attr('data-person-id', response.nturnerin?.id ?? 0);
$(".submit-display-turnerin").css("opacity", "1");
$(".submit-display-start").css("opacity", "1");
$(".submit-display-result").css("opacity", "1");
const $editAllDiv = $('.div_edit_values_all_gereate');
const noten = response.noten;
const programmId = response.programm_id;
// First, reset all containers to a single input state and clear values
$editAllDiv.find('.note-container').each(function() {
const $container = $(this);
const $tbody = $container.find('tbody');
const $headerRow = $container.find('thead tr');
// Reset header
$headerRow.find('.run-num-header').remove();
// Remove extra inputs beyond run 1
$tbody.find('.inputs-row').each(function() {
$(this).find('td:not(.input-cell-run-1)').remove();
});
// Clear value of run 1
$container.find('input[data-run="1"]').val('').attr('data-person-id', response.id);
});
// Now loop through the data and populate/expand
for (const [geraetId, noteGroup] of Object.entries(noten)) {
for (const [noteId, runGroup] of Object.entries(noteGroup)) {
const $container = $editAllDiv.find(`.note-container[data-note-id="${noteId}"]`);
if ($container.length === 0) continue;
const $tbody = $container.find('tbody');
const $headerRow = $container.find('thead tr');
const $inputsRow = $tbody.find('.inputs-row');
const runCount = Object.keys(runGroup).length;
$headerRow.find('.note-name-header .rm').remove();
const originalText = $headerRow.find('.note-name-header').text().trim();
// If more than 1 run, add headers if not already present
if (runCount > 1 && $headerRow.find('.run-num-header').length === 0) {
$headerRow.find('.note-name-header').html(originalText + ' <span class="rm">(R1)</span>');
for (let r = 2; r <= runCount; r++) {
$headerRow.append(`<th class="run-num-header">${originalText} <span class="rm">(R${r})</span></th>`);
}
}
for (const [runNum, val] of Object.entries(runGroup)) {
let $input = $inputsRow.find(`input[data-run="${runNum}"][data-geraet-id="${geraetId}"]`);
// If input doesn't exist yet (for Run 2+), clone it
if ($input.length === 0) {
const $cell1 = $inputsRow.find('.input-cell-run-1');
const $newCell = $cell1.clone();
$newCell.removeClass('input-cell-run-1').addClass(`input-cell-run-${runNum}`);
$input = $newCell.find('input');
$input.attr('data-run', runNum).val(val ?? '');
$inputsRow.append($newCell);
// Re-bind change event to new input
//bindAjaxInput($input);
} else {
$input.val(val ?? '').attr('data-person-id', response.id);
}
}
}
}
$(".submit-display-turnerin").attr('data-person-id', response.id);
$(".submit-display-start").attr('data-person-id', response.id);
const submitMusikStart = $(".submit-musik-start");
const submitMusikStopp = $(".submit-musik-stopp");
if (submitMusikStart.length > 0 && submitMusikStopp.length > 0){
submitMusikStart.attr('data-id', response.id);
submitMusikStopp.attr('data-id', response.id);
}
$(".submit-display-result").attr('data-person-id', response.id);
} else {
displayMsg(0, response.message);
$input.css({
'background-color': '#f8d7da',
'color': '#fff',
'transition': 'all 0.3s ease-out'
});
setTimeout(() => $input.css({
'background-color': '',
'color': ''
}), 2000);
}
})
.catch(err => {
$input.css('background-color', '#f8d7da');
console.error('AJAX fetch error:', err);
});
});
};
jQuery(document).ready(function($) {
$('.editTurnerin').on('click', function() {
$(this).updateCurrentEdit();
});
function bindAjaxInput($el) {
$el.on('change', function() {
const start = performance.now();
const $input = $(this);
const url = `/intern/scripts/kampfrichter/ajax/ajax-update_value_kampfrichter.php`;
personId = $input.data('person-id');
fieldTypeId = $input.data('field-type-id');
gereatId = $input.data('geraet-id');
runNum = $input.attr('data-run') || 1;
jahr = window.AKTUELLES_JAHR;
value = $input.val();
fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
personId: personId,
fieldTypeId: fieldTypeId,
gereatId: gereatId,
run: runNum,
jahr: jahr,
value: value
})
})
.then(res => res.json())
.then(response => {
const end = performance.now();
console.log(`Total AJAX time: ${(end - start).toFixed(3)} ms`);
if (response.success) {
let objValues = [];
const rowId = $input.attr('data-id');
$input.css({"color": "#0e670d", "font-weight": "600"});
setTimeout(() => $input.css({'color': '', "font-weight": ""}), 2000);
const noten = response.noten;
for (const [keyN, noteGroup] of Object.entries(noten)) {
for (const [key, runGroup] of Object.entries(noteGroup)) {
if (key == fieldTypeId && keyN == gereatId) { continue; }
for (const [run, value] of Object.entries(runGroup)) {
$(`input.changebleValue[data-field-type-id="${key}"][data-geraet-id="${keyN}"][data-person-id="${personId}"][data-run="${run}"]`)
.val(value ?? '');
$(`.changebleValue:not(input)[data-field-type-id="${key}"][data-geraet-id="${keyN}"][data-person-id="${personId}"][data-run="${run}"]`)
.text(value ?? '');
}
}
}
ws.send(JSON.stringify({
type: "KAMPFRICHTER_UPDATE",
payload: {
discipline: window.FREIGABE,
gereatId: gereatId,
personId: personId,
jahr: jahr,
noten: noten
}
}));
} else {
// Flash red on error
$input.css({'color': '#ff6a76ff'});
displayMsg(0, response.message || 'Unknown error');
console.error(response.message || 'Unknown error');
}
})
.catch(err => {
$input.css({'color': '#670d0d'});
console.error('AJAX fetch error:', err);
});
});
}
$('.ajax-input').each(function() {
bindAjaxInput($(this));
});
/*$('.ranglisteExport').on('click', function(e) {
const $input = $(this);
if ($input.data('field_type') !== 'upload_programm') {e.preventDefault();}
// Build the data to send
const data = new URLSearchParams();
data.append('prog', $input.data('id'));
data.append('type', $input.data('field_type'));
// Record start time
const start = performance.now();
const url = '/intern/scripts/kampfrichter/ajax/ajax-neu_rangliste.php';
fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
prog: $input.data('id'),
type: $input.data('field_type')
})
})
.then(res => res.blob())
.then(blob => {
if ($input.data('field_type') !== 'upload_programm'){
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = "KTBB_Ergebnisse.pdf"; // optional
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
} else {
alert('PDF auf Webseite geladen!');
}
});
});
$('.protokollExport').on('click', function() {
console.log('ok');
const $input = $(this);
// Build the data to send
const data = new URLSearchParams();
data.append('abteilung', $input.data('abteilung'));
// Record start time
const start = performance.now();
const url = '/intern/scripts/kampfrichter/ajax/ajax-neu_protokoll.php';
fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
abteilung: $input.data('abteilung')
})
})
.then(res => res.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = "KTBB_Protokoll.pdf"; // optional
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
});
});*/
$('.inputnamekr').on('change', function() {
const $input = $(this);
const url = '/intern/scripts/kampfrichter/ajax/ajax-update_name_kampfrichter_protokoll.php';
fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
aufgabe: $input.data('id'),
abteilung: $input.data('abt'),
geraet: $input.data('user'),
name: $input.val()
})
})
.then(res => res.json())
.then(response => {
if (response.success) {
console.log(response.message);
$input.css({
'background-color': '#a4bf4a',
'color': '#fff',
'transition': 'all 0.3s ease-out'
});
setTimeout(() => $input.css({
'background-color': '',
'color': ''
}), 2000);
} else {
console.error(response.message);
$input.css({
'background-color': '#f8d7da',
'color': '#fff',
'transition': 'all 0.3s ease-out'
});
setTimeout(() => $input.css({
'background-color': '',
'color': ''
}), 2000);
}
})
.catch(err => {
$input.css('background-color', '#f8d7da');
console.error('AJAX fetch error:', err);
displayMsg(0, 'AJAX fetch error:' + err);
});
});
/**
* Handle namekr input updates
$('.ajax-input-namekr').on('change', function() {
let $input = $(this);
$.post(ajax_object.ajaxurl, {
action: 'save_namekr_input',
id: $input.data('id'),
abt: $input.data('abt'),
user: $input.data('user'),
value: $input.val()
}, function(response) {
if (response.success) {
console.log(response.data.message);
$input.css({
'background-color': '#a4bf4a',
'color': '#fff',
'transition': 'all 0.3s ease-out'
});
setTimeout(() => $input.css({
'background-color': '',
'color': ''
}), 2000);
} else {
console.error(response.data.message);
$input.css({
'background-color': '#f8d7da',
'color': '#fff',
'transition': 'all 0.3s ease-out'
});
setTimeout(() => $input.css({
'background-color': '',
'color': ''
}), 2000);
}
}, 'json');
}); */
/**
* Handle display JSON updates
*/
$('.submit-display-turnerin').on('click', function() {
const $input = $(this);
// Build the URL with GET parameters safely
const url = '/intern/scripts/kampfrichter/ajax/displays/ajax-display-functions.php';
fetch(url,{
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
personId: $input.attr('data-person-id'),
geraetId: $input.attr('data-geraet-id'),
jahr: window.AKTUELLES_JAHR,
type: "neu"
})
})
.then(res => res.json())
.then(response => {
if (response.success) {
ws.send(JSON.stringify({
type: "UPDATE_SCORE",
payload: {
geraet: response.nameGeraet,
data: response.data
}
}));
displayMsg(1, 'Neue Turnerin wird angezigt');
$input.css('opacity', 0.5);
} else {
displayMsg(0, response.message);
}
})
.catch(err => {
$input.css('background-color', '#f8d7da');
displayMsg(0, 'AJAX fetch error:' + err);
console.error('AJAX fetch error:', err);
});
});
$('.submit-display-start').on('click', function() {
const $input = $(this);
const url = '/intern/scripts/kampfrichter/ajax/displays/ajax-display-functions.php';
fetch(url,{
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
geraetId: $input.attr('data-geraet-id'),
type: "start"
})
})
.then(res => res.json())
.then(response => {
if (response.success) {
ws.send(JSON.stringify({
type: "UPDATE_SCORE",
payload: {
geraet: response.nameGeraet,
data: response.data
}
}));
displayMsg(1, 'Start freigegeben');
$input.css('opacity', 0.5);
} else {
alert('Error: ' + response.message);
}
})
.catch(err => {
$input.css('background-color', '#f8d7da');
displayMsg(0, 'AJAX fetch error:' + err);
console.error('AJAX fetch error:', err);
});
});
/*$('.submit-display-start').on('click', function() {
let discipline = $(this).data('discipline');
$.post(ajax_object.ajaxurl, {
action: 'write_discipline_json_start',
discipline: discipline
}, function(response) {
if (response.success) {
alert('Start freigegeben');
if (response.data.disable_start_button) {
$('.submit-display-start').css({
'border': '1px solid #aaa',
'background-color': '#aaa',
'color': '#555',
'pointer-events': 'none'
});
$('.submit-musik-start').css({
'background-color': '#077',
'border': '1px solid #077',
'color': '#fff',
'cursor': 'pointer',
'pointer-events': 'auto'
});
}
} else {
alert('Error: ' + response.data.message);
}
}, 'json');
});*/
$('.submit-musik-start').on('click', function() {
const $input = $(this);
// Build the URL with GET parameters safely
const url = `/intern/scripts/kampfrichter/ajax/ajax-update_kampfrichter_start_musik.php` +
`?id=${$input.attr('data-id')}` +
`&discipline=${encodeURIComponent($input.data('geraet'))}`;
fetch(url)
.then(res => res.json())
.then(response => {
const end = performance.now();
ws.send(JSON.stringify({
type: "AUDIO",
payload: {}
}));
if (response.success) {
displayMsg(1, 'Musik wird abgespielt werden');
} else {
displayMsg(0, 'Error: ' + response.message);
}
})
.catch(err => {
$input.css('background-color', '#f8d7da');
displayMsg(0, 'AJAX fetch error:' + err);
console.error('AJAX fetch error:', err);
});
});
$('.submit-musik-stopp').on('click', function() {
const $input = $(this);
// Build the URL with GET parameters safely
const url = `/intern/scripts/kampfrichter/ajax/ajax-update_kampfrichter_stopp_musik.php`;
fetch(url)
.then(res => res.json())
.then(response => {
if (response.success) {
ws.send(JSON.stringify({
type: "AUDIO",
payload: {}
}));
displayMsg(1, 'Musik wird gestoppt werden');
} else {
alert('Error: ' + response.message);
}
})
.catch(err => {
$input.css('background-color', '#f8d7da');
displayMsg(0, 'AJAX fetch error:' + err);
console.error('AJAX fetch error:', err);
});
});
$('.submit-display-result').on('click', function() {
$input = $(this);
// Build the URL with GET parameters safely
const url = '/intern/scripts/kampfrichter/ajax/displays/ajax-display-functions.php';
fetch(url,{
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
personId: $input.attr('data-person-id'),
geraetId: $input.attr('data-geraet-id'),
jahr: window.AKTUELLES_JAHR,
type: "result"
})
})
.then(res => res.json())
.then(response => {
if (response.success) {
ws.send(JSON.stringify({
type: "UPDATE_SCORE",
payload: {
geraet: response.nameGeraet,
data: response.data
}
}));
$input.css('opacity', 0.5);
displayMsg(1, 'Resultat wird angezeigt');
} else {
alert('Error: ' + response.message);
}
})
.catch(err => {
$input.css('background-color', '#f8d7da');
displayMsg(0, 'AJAX fetch error:' + err);
console.error('AJAX fetch error:', err);
});
});
});
const selecteddiscipline = window.FREIGABE;
ws.addEventListener("message", event => { // Use 'event' as it's more standard than 'blob'
let msgOBJ;
try {
msgOBJ = JSON.parse(event.data);
} catch (error) {
return;
}
// Ensure it's an UPDATE type (matches your sendToGroup logic)
if (msgOBJ?.type === "UPDATE") {
const data = msgOBJ.payload;
// Check access rights
if (data.discipline === selecteddiscipline.toLowerCase() || selecteddiscipline.toLowerCase() === 'admin') {
const noten = data.noten;
for (const [keyG, noteGroup] of Object.entries(noten)) {
for (const [key, runGroup] of Object.entries(noteGroup)) {
for (const [run, value] of Object.entries(runGroup)) {
// OPTIONAL: Skip if the current user is currently focused on this specific input
if (document.activeElement.dataset.fieldTypeId === key &&
document.activeElement.dataset.geraetId === keyG &&
document.activeElement.dataset.run == run) continue;
// Select all matching elements (inputs and spans)
const $elements = $(`.changebleValue[data-field-type-id="${key}"][data-geraet-id="${keyG}"][data-person-id="${data.personId}"][data-run="${run}"]`);
$elements.each(function() {
const $el = $(this);
// Update value or text
if ($el.is('input')) {
$el.val(value ?? '');
} else {
$el.text(value ?? '');
}
// Visual feedback: Flash color
const nativeEl = $el[0];
nativeEl.style.transition = 'color 0.3s';
nativeEl.style.color = '#008e85';
setTimeout(() => {
nativeEl.style.color = '';
}, 1000);
});
}
}
}
}
}
});
/*document.getElementById('freigabe-select').addEventListener('change', function() {
const freigabe = this.value;
const user_id = document.getElementById('user_id').value;
const nonce = document.getElementById('freigabe_nonce').value;
const type = document.getElementById('type_freigabe').value;
const params = new URLSearchParams();
params.append('action', 'save_freigabe');
params.append('freigabe', freigabe);
params.append('user_id', user_id);
params.append('type', type);
fetch('/intern/scripts/kampfrichter/ajax/ajax-update_selected_kampfrichter.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params
})
.then(res => res.json())
.then(data => {
if (data.success) {
window.location.reload();
} else {
alert('Error: ' + data.data);
}
})
.catch(err => {
console.error(err);
displayMsg(0, 'AJAX fetch error:' + err);
});
});*/

View File

@@ -0,0 +1,34 @@
function allNameKrValid() {
var isValid = true;
$('.ajax-input-namekr').each(function () {
if ($(this).val() === '---') {
isValid = false;
return false; // break loop
}
});
return isValid;
}
function updateSelectKrDiv() {
const krDiv = $('.noKampfrichterDiv');
if (krDiv.length !== 1) {
return;
}
if (allNameKrValid()) {
krDiv.css('display', 'none');
} else {
krDiv.css('display', 'flex');
}
}
// initial check
updateSelectKrDiv();
// react to changes
$('.ajax-input-namekr').on('change', function () {
updateSelectKrDiv();
});

View File

@@ -0,0 +1,84 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
$token = isset($_GET['token']) ? $_GET['token'] : '';
if ($token !== 'sWZ4GxbsoVhUPk5zhjH0uU9hets3zV2KsV8CZUvAWCCRk4uuuDr9vfFVgxWqr5FtDttbtm50EdWK9YxuMPswGZBQZFHAUAET1aG1'){
echo json_encode(['success' => false, 'message' => '500 Error - Critical Server Error']);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$value = isset($_GET['value']) ? preg_replace('/[^a-zA-Z0-9\s\-"]/u', '', $_GET['value']) : '';
if (!$value || $value === ''){
echo json_encode(['success' => false, 'message' => 'No input']);
exit;
}
// ---------- Step 2: Get values from DB ----------
$stmt = $mysqli->prepare("INSERT INTO `$tableProgramme` (programm) VALUES (?)");
if (!$stmt) {
echo json_encode(['success' => false, 'message' => 'Critical DB ERROR']);
exit;
}
$stmt->bind_param("s", $value);
$success = $stmt->execute();
$stmt->close();
if (!$success) {
echo json_encode(['success' => false, 'message' => 'Insert failed']);
exit;
}
// Fetch all rows
$query2 = "SELECT * FROM `$tableProgramme` ORDER BY programm ASC";
$programme = $mysqli->query($query2);
if (!$programme) {
echo json_encode(['success' => false, 'message' => 'Select failed']);
exit;
}
$output = [];
while ($entry = $programme->fetch_assoc()) {
$output[] = [
'id' => $entry['id'],
'programm' => $entry['programm'],
'aktiv' => intval($entry['aktiv']),
'preis' => floatval($entry['preis'])
];
}
// Return JSON
echo json_encode([
'success' => true,
'output' => $output,
'message' => $value.' hinzugefügt'
]);
exit;

View File

@@ -0,0 +1,89 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
$token = isset($_GET['token']) ? $_GET['token'] : '';
if ($token !== 'bKqBAPjwojZdarJaE7jwvRrIEf2WzJUlFlufQadfLJ98qJcrWZK5pRlGoUQOHp1L06urGRbEdE9v5oIRirPiUCjm93wATghO4qx'){
echo json_encode(['success' => false, 'message' => '500 Error - Critical Server Error']);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
// ---------- Step 2: Get values from DB ----------
$stmt = $mysqli->prepare("DELETE FROM `$tableProgramme` WHERE id = ?");
if (!$stmt) {
echo json_encode(['success' => false, 'message' => 'Critical DB ERROR']);
exit;
}
$stmt->bind_param("i", $id);
$success = $stmt->execute();
$stmt->close();
if (!$success) {
echo json_encode(['success' => false, 'message' => 'Insert failed']);
exit;
}
// Fetch all rows
$query2 = "SELECT * FROM `$tableProgramme` ORDER BY programm ASC";
$programme = $mysqli->query($query2);
if (!$programme) {
echo json_encode(['success' => false, 'message' => 'Select failed']);
exit;
}
$output = [];
while ($entry = $programme->fetch_assoc()) {
$output[] = [
'id' => $entry['id'],
'programm' => $entry['programm'],
'aktiv' => intval($entry['aktiv']),
'preis' => floatval($entry['preis'])
];
}
// Return JSON
echo json_encode([
'success' => true,
'output' => $output,
'message' => $id.' gelöscht'
]);
exit;

View File

@@ -0,0 +1,159 @@
<?php
use Dotenv\Dotenv;
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
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;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/csrf_functions.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo json_encode(['success' => false, 'message' => 'Critical DB Error.']);
exit;
}
if (isset($_POST['field_id'])){
$id = intval($_POST['field_id']);
} else {
echo json_encode(['success' => false, 'message' => 'Invalid Input.']);
exit;
}
$editor_id = $_SESSION['passcodewk_leitung_id'];
$plain = trim($_POST['password'] ?? '');
if (!$plain) {
echo json_encode(['success' => false, 'message' => 'Invalid Input.']);
exit;
}
$username = htmlspecialchars(trim($_POST['username'] ?? ''));
if (!$username) {
echo json_encode(['success' => false, 'message' => 'Invalid Input.']);
exit;
}
$freigaben = $_POST['freigaben'] ?? [];
$freigabenTrainer = $_POST['freigabenTrainer'] ?? [];
$freigabenKampfrichter = $_POST['freigabenKampfrichter'] ?? [];
if (!is_array($freigaben)) {
$freigaben = [];
}
if (!is_array($freigabenTrainer)) {
$freigabenTrainer = [];
}
if (!is_array($freigabenKampfrichter)) {
$freigabenKampfrichter = [];
}
$array = [
'types' => $freigaben,
'freigabenTrainer' => $freigabenTrainer,
'freigabenKampfrichter' => $freigabenKampfrichter
];
// Store as proper JSON string
$freigabe_store = json_encode($array);
// Hash for login
$hash = password_hash($plain, PASSWORD_ARGON2ID);
require $baseDir . '/../composer/vendor/autoload.php';
$envFile = realpath($baseDir . '/../config/.env.pw-encryption-key');
if ($envFile === false) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => "Environment file not found"
]);
exit;
}
try {
$envDir = dirname($envFile);
$dotenv = Dotenv::createImmutable($envDir, '.env.pw-encryption-key');
$dotenv->load();
} catch (Throwable $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => "Dotenv error"
]);
}
// Encrypt for display
$iv_length = openssl_cipher_iv_length('aes-256-cbc');
$iv = random_bytes($iv_length);
$encrypted = openssl_encrypt($plain, 'aes-256-cbc', $_ENV['PW_ENCRYPTION_KEY'], 0, $iv);
$cipher_store = base64_encode($iv . $encrypted);
if ($id > 0) {
$updated = db_update($mysqli, $tableInternUsers, [
'password_hash' => $hash,
'password_cipher' => $cipher_store,
'username' => $username,
'freigabe' => $freigabe_store,
'updated_at' => date('Y-m-d H:i:s'),
'edited_by' => $editor_id
], ['id' => $id]);
} else {
$stmt = $mysqli->prepare(
"INSERT INTO {$tableInternUsers}
(username, password_hash, password_cipher, freigabe, created_at, updated_at, edited_by)
VALUES (?, ?, ?, ?, ?, ?, ?)"
);
$stmt->bind_param(
"ssssssi",
$username,
$hash,
$cipher_store,
$freigabe_store,
$created_at,
$updated_at,
$editor_id
);
$created_at = date('Y-m-d H:i:s');
$updated_at = $created_at;
$updated = $stmt->execute();
}
if ($updated !== false) {
if ($id == 0) { // new user
$new_id = $mysqli->insert_id;
echo json_encode(['success' => true, 'message' => $username.' wurde erfolgreich erstellt.', 'id' => $new_id]);
} else {
echo json_encode(['success' => true, 'message' => $username.' wurde erfolgreich aktualisiert.']);
}
} else {
echo json_encode(['success' => false, 'message' => 'DB Error']);
}

View File

@@ -0,0 +1,60 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
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;
}
$token = isset($_GET['token']) ? $_GET['token'] : '';
if ($token !== '0UgBVHutbxTRTYsB04ujFKMjMRA8GgdqRJjVh3DKU1LRJfwtcDfrpDc7jpMxcrg9rYurAEwYPy5gu15R77MsgKsDMkFZEykx0A67'){
echo json_encode(['success' => false, 'message' => '500 Error - Critical Server Error']);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
// ---------- Get and sanitize input ----------
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$value = isset($_GET['value']) ? floatval($_GET['value']) : 0;
if ($id < 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
// ---------- Step 2: Get values from DB ----------
$query = "UPDATE `$tableProgramme` SET aktiv = '$value' WHERE id = $id";
$result = $mysqli->query($query);
if (!$result) {
echo json_encode(['success' => false, 'message' => 'Update failed']);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'Aktualisiert'
]);
exit;

View File

@@ -0,0 +1,60 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
$token = isset($_GET['token']) ? $_GET['token'] : '';
if ($token !== 'k7uweziEUWZiJhwe7687UWIQZ28SQIH2ug74pINKyxHxPerB6wUZ'){
echo json_encode(['success' => false, 'message' => '500 Error - Critical Server Error']);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
// ---------- Get and sanitize input ----------
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
$value = isset($_GET['value']) ? round(floatval($_GET['value']), 2) : 0;
if ($id < 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
// ---------- Step 2: Get values from DB ----------
$query = "UPDATE `$tableProgramme` SET preis = '$value' WHERE id = $id";
$result = $mysqli->query($query);
if (!$result) {
echo json_encode(['success' => false, 'message' => 'Update failed']);
exit;
}
// ---------- Return JSON ----------
echo json_encode([
'success' => true,
'message' => 'Startgebüren set to '.$value.' Fr.'
]);
exit;

View File

@@ -0,0 +1,67 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
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;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/csrf_functions.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo json_encode(['success' => false, 'message' => 'Critical DB Error.']);
exit;
}
$id = intval($_POST['field_id']) ?? '';
$verein = htmlspecialchars(trim($_POST['verein'] ?? ''));
if (!isset($id) || !is_int($id) || !isset($verein)){
echo json_encode(['success' => false, 'message' => 'Invalid Input.']);
exit;
}
if ($id > 0) {
$updated = db_update($mysqli, $tableVereine, [
'verein' => $verein,
], ['id' => $id]);
} else {
$stmt = $mysqli->prepare(
"INSERT INTO {$tableVereine}
(verein)
VALUES (?)"
);
$stmt->bind_param(
"s",
$verein
);
$updated = $stmt->execute();
}
if ($updated !== false) {
if ($id == 0) { // new user
$new_id = $mysqli->insert_id;
echo json_encode(['success' => true, 'message' => $verein.' wurde erfolgreich erstellt.', 'id' => $new_id]);
} else {
echo json_encode(['success' => true, 'message' => $verein.' wurde erfolgreich aktualisiert.']);
}
} else {
echo json_encode(['success' => false, 'message' => 'DB Error']);
}

View File

@@ -0,0 +1,46 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
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;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/csrf_functions.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo json_encode(['success' => false, 'message' => 'Critical DB Error.']);
exit;
}
$id = intval($_POST['field_id'] ?? 0);
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid Input.']);
exit;
}
$deleted = db_delete($mysqli, $tableInternUsers, ['id' => $id]);
if ($deleted !== true) {
// DB query failed (syntax/connection issue)
echo json_encode(['success' => false, 'message' => 'DB Error.']);
exit;
} else {
// Success
echo json_encode(['success' => true, 'message' => "Benutzer $id erfolgreich gelöscht.", 'id' => $id]);
exit;
}

View File

@@ -0,0 +1,36 @@
<?php
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
}
$id = intval($_POST['field_id'] ?? 0);
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'No valid ID']);
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/csrf_functions.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo 'Critical DB Error.';
exit;
}
if (!db_delete($mysqli, $tableVereine, ['id' => $id])) {
echo json_encode(['success' => false, 'message' => 'Failed to delete verein']);
exit;
}
echo json_encode(['success' => true, 'message' => '200, ok']);

View File

@@ -0,0 +1,61 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
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;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/csrf_functions.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo 'Critical DB Error.';
exit;
}
$id = intval($_POST['user_id'] ?? 0);
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'No valid ID']);
exit;
}
// Delete old OTL links for this user (recommended)
db_delete($mysqli, $tableOTL, ['user_id' => $id]);
// Insert the row — url + timestamp are auto-generated by MySQL
$stmt = $mysqli->prepare("INSERT INTO {$tableOTL} (user_id) VALUES (?)");
$stmt->bind_param("i", $id);
if (!$stmt->execute()) {
echo json_encode(['success' => false, 'message' => 'Failed to create OTL record']);
exit;
}
$row_id = $stmt->insert_id;
$stmt->close();
// Now fetch the auto-generated URL
$url = db_get_var($mysqli, "SELECT url FROM $tableOTL WHERE id = ? LIMIT 1", [$row_id]);
if (!$url) {
echo json_encode(['success' => false, 'message' => 'Could not fetch generated URL']);
exit;
}
echo json_encode(['success' => true, 'url' => $url]);

View File

@@ -0,0 +1,73 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
http_response_code(500);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
if (!isset($_POST['ids']) || !is_array($_POST['ids']) || count($_POST['ids']) < 1) {
echo json_encode(['success' => false, 'message' => 'Keine Id angegeben']);
http_response_code(422);
exit;
}
$ids = $_POST['ids'];
// Validate: all IDs must be integers
$ids = array_filter($ids, fn($id) => ctype_digit(strval($id)));
if (count($ids) === 0) {
echo json_encode(['success' => false, 'message' => 'Kein gültiger Input']);
http_response_code(422);
exit;
}
// Build placeholders for prepared statement
$placeholders = implode(',', array_fill(0, count($ids), '?'));
// Prepare the SQL statement
$sql = "DELETE FROM $tableOrders WHERE order_id IN ($placeholders)";
$stmt = $mysqli->prepare($sql);
if (!$stmt) {
echo json_encode(['success' => false, 'message' => 'Fehler beim Vorbereiten der Abfrage']);
http_response_code(500);
exit;
}
// Bind parameters dynamically
$types = str_repeat('i', count($ids)); // all integers
$stmt->bind_param($types, ...$ids);
// Execute
if (!$stmt->execute()) {
echo json_encode(['success' => false, 'message' => 'Fehler beim Löschen']);
http_response_code(500);
exit;
}
$stmt->close();
$mysqli->close();
echo json_encode(['success' => true, 'message' => 'Bestellungen erfolgreich gelöscht']);
http_response_code(200);
exit;

View File

@@ -0,0 +1,69 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
http_response_code(500);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
if (!isset($_POST['scor']) || empty($_POST['scor']) || $_POST['scor'] === '') {
echo json_encode(['success' => false, 'message' => 'Keine Referenz angegeben']);
http_response_code(422);
exit;
}
$scorFullStr = strval($_POST['scor']);
$scor = intval(substr($scorFullStr, 2));
$stmt = $mysqli->prepare(
"SELECT 1 FROM $tableOrders WHERE order_id = ? LIMIT 1"
);
$stmt->bind_param('i', $scor);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows !== 1) {
echo json_encode(['success' => false, 'message' => 'Invalide Referenz']);
http_response_code(403);
exit;
}
$stmt->close();
$sql = "UPDATE $tableOrders SET order_status = 2 WHERE order_id = ?";
$nstmt = $mysqli->prepare($sql);
$nstmt->bind_param('i', $scor);
if (!$nstmt->execute()) {
echo json_encode(['success' => false, 'message' => 'Fehler']);
http_response_code(500);
exit;
}
$nstmt->close();
$mysqli->close();
echo json_encode(['success' => true, 'message' => 'Rechnung wurde aktualisiert']);
http_response_code(200);
exit;

View File

@@ -0,0 +1,233 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
// Show all errors except deprecation notices (these come from vendor libraries
// that aren't yet typed for newer PHP versions). Long-term fix: update
// dependencies to versions compatible with your PHP runtime.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo 'Critical DB Error.';
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$allGeraete = db_select($mysqli, $tableGeraete, "id, name, start_index", "", [], "start_index ASC");
$allAbt = db_select($mysqli, $tableAbt, "name, id", "", [], "name ASC");
$maxTurnerinnenGruppe = 8;
// $allGeraete[] = ['name' => 'null', 'id' => 'null'];
// $allAbt[] = ['name' => 'null', 'id' => 'null'];
/*$stmt = $mysqli->prepare("
SELECT
t.id,
t.programm,
t.verein,
GROUP_CONCAT(ta.id SEPARATOR ', ') AS abt_table_id
FROM $tableTurnerinnen t
LEFT JOIN $tableTurnerinnenAbt ta ON ta.turnerin_id = t.id
GROUP BY t.id, t.programm, t.verein
ORDER BY t.id DESC
");
$stmt->execute();
$result = $stmt->get_result();
$allTurnerinnen = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
print_r($allTurnerinnen);*/
$allTurnerinnen = db_select($mysqli, $tableTurnerinnen, "id, programm, verein, name" , "", [], "programm ASC");
$grouped = [];
foreach ($allTurnerinnen as $t) {
$sanitasedprogramm = str_replace(['-kader'], '', strtolower($t['programm']));
$grouped[$sanitasedprogramm][$t['verein']][] = $t;
}
function getMinKey(array $array): string|int {
return array_search(min($array), $array, true);
}
function arrayRiegeneiteilung($allturnerinnen, $maxTurnerinnenGruppe, $allGeraete) {
$indabt = 1;
$arrayAutoRiegeneinteilung = [];
foreach ($allturnerinnen as $prog => $vereine) {
// ABTEILUNG BERECHNEN
$countturterinnenprog = 0;
foreach ($vereine as $verein => $turnerinnen) {
foreach ($turnerinnen as $ind => $turnerin) {
$countturterinnenprog++;
$abt = intdiv($countturterinnenprog, $maxTurnerinnenGruppe * count($allGeraete)) + $indabt;
$allturnerinnen[$prog][$verein][$ind]['abt'] = $abt;
$arrayAbt[$abt][$verein][] = $turnerin;
}
}
$indabt += intdiv($countturterinnenprog - 1, $maxTurnerinnenGruppe * count($allGeraete)) + 1;
}
foreach ($arrayAbt as $abt => $vereine) {
// AUSGLEICHEN DER GRUPPEN
$arrayAbt = [];
$arrayGruppen = [];
foreach ($allGeraete as $geraet) {
$arrayGruppen[$geraet['id']] = 0;
}
$turnerinnenCount = 0;
foreach ($vereine as $verein => $turnerinnen) {
$turnerinnenCount += count($turnerinnen);
}
foreach ($vereine as $verein => $turnerinnen) {
if (count($turnerinnen) > $maxTurnerinnenGruppe || count($turnerinnen) > $turnerinnenCount / count($allGeraete)) {
if (count($turnerinnen) > $turnerinnenCount / count($allGeraete)) {
$maxTurnerinnenGruppeTemp = ceil($turnerinnenCount / count($allGeraete));
} else {
$maxTurnerinnenGruppeTemp = $maxTurnerinnenGruppe;
}
// AUFTEILEN IN MEHRERE GRUPPEN
$chunks = array_chunk($turnerinnen, $maxTurnerinnenGruppeTemp);
foreach ($chunks as $chunk) {
$minKey = getMinKey($arrayGruppen);
$arrayGruppen[$minKey] += count($chunk);
foreach ($chunk as $ind =>$turnerin) {
$arrayAutoRiegeneinteilung[$abt][$minKey][] = $turnerin;
}
}
continue;
}
$minKey = getMinKey($arrayGruppen);
$arrayGruppen[$minKey] += count($turnerinnen);
foreach ($turnerinnen as $ind =>$turnerin) {
$arrayAutoRiegeneinteilung[$abt][$minKey][] = $turnerin;
}
}
}
foreach ($arrayAutoRiegeneinteilung as $indAbt => $abt) {
foreach ($abt as $indGeraet => $geraet) {
foreach ($geraet as $indTurnerin => $turnerin) {
$arrayAutoRiegeneinteilung[$indAbt][$indGeraet][$indTurnerin]['turnerin_index'] = $indTurnerin + 1;
}
}
}
return $arrayAutoRiegeneinteilung;
}
$arrayAutoRiegeneinteilung = arrayRiegeneiteilung($grouped, $maxTurnerinnenGruppe, $allGeraete);
$stmt = $mysqli->prepare("DELETE FROM $tableTurnerinnenAbt");
$stmt->execute();
$stmt->close();
$stmt = $mysqli->prepare("DELETE FROM $tableAbt");
$stmt->execute();
$stmt->close();
foreach ($arrayAutoRiegeneinteilung as $indAbt => $abt) {
$stmt = $mysqli->prepare("INSERT INTO $tableAbt (name) VALUES (?)");
$stmt->bind_param("s", $indAbt);
$stmt->execute();
$idAbt = $stmt->insert_id;
$stmt->close();
foreach ($abt as $indGeraet => $geraet) {
foreach ($geraet as $indTurnerin => $turnerin) {
$stmt = $mysqli->prepare("INSERT INTO $tableTurnerinnenAbt (turnerin_id, abteilung_id, geraet_id, turnerin_index) VALUES (?, ?, ?, ?)");
$stmt->bind_param("ssss", $turnerin['id'], $idAbt, $indGeraet, $turnerin['turnerin_index']);
$stmt->execute();
$stmt->close();
}
}
}
return http_response_code(201);
/*foreach ($grouped as $ind => $g) {
echo $ind;
foreach ($g as $verein) {
foreach ($verein as $turnerin) {
echo '<div class="riegeneinteilung_turnerin_row" data-turnerin_id="' . $turnerin['id'] . '">';
echo '<div class="riegeneinteilung_turnerin_info">';
echo '<span class="riegeneinteilung_turnerin_name">' . htmlspecialchars($turnerin['name']) . '</span>';
echo '<span class="riegeneinteilung_turnerin_verein">(' . htmlspecialchars($turnerin['verein']) . ')</span>';
echo '<span class="riegeneinteilung_turnerin_verein">(' . htmlspecialchars($turnerin['abt']) . ')</span>';
echo '<span class="riegeneinteilung_turnerin_verein">(' . htmlspecialchars($turnerin['geraet_id']) . ')</span>';
echo '</div>';
echo '</div></div>';
}
}
echo '<br><br>';
}
foreach ($arrayAutoRiegeneinteilung as $ind => $abt) {
echo '<br>ABT:' . $ind;
foreach ($abt as $g) {
echo '<br>GERÄT';
foreach ($g as $turnerin) {
echo '<div class="riegeneinteilung_turnerin_row" data-turnerin_id="' . $turnerin['id'] . '">';
echo '<div class="riegeneinteilung_turnerin_info">';
echo '<span class="riegeneinteilung_turnerin_name">' . htmlspecialchars($turnerin['name']) . '</span>';
echo '<span class="riegeneinteilung_turnerin_verein">(' . htmlspecialchars($turnerin['verein']) . ')</span>';
echo '<span class="riegeneinteilung_turnerin_verein">(' . htmlspecialchars($turnerin['turnerin_index']) . ')</span>';
echo '<span class="riegeneinteilung_turnerin_verein">(' . htmlspecialchars($turnerin['programm']) . ')</span>';
echo '</div>';
echo '</div></div>';
}
}
echo '<br><br>';
}
print_r($arrayAutoRiegeneinteilung);*/

View File

@@ -0,0 +1,66 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
// Show all errors except deprecation notices (these come from vendor libraries
// that aren't yet typed for newer PHP versions). Long-term fix: update
// dependencies to versions compatible with your PHP runtime.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
// Validate input
if (!isset($_POST['anz_abt']) || !ctype_digit($_POST['anz_abt'])) {
http_response_code(406);
exit;
}
$anz_abt = (int) $_POST['anz_abt'];
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo 'Critical DB Error.';
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
// Fetch existing Abteilungen
$abts = db_select($mysqli, $tableAbt, '*');
// Delete excess Abteilungen
foreach ($abts as $dbabt) {
if ((int)$dbabt['name'] > $anz_abt) {
db_delete($mysqli, $tableAbt, ['name' => $dbabt['name']]);
}
}
// Build lookup of existing names
$existing = array_map('intval', array_column($abts, 'name'));
// Insert missing Abteilungen
$stmt = $mysqli->prepare("INSERT INTO $tableAbt (name) VALUES (?)");
for ($i = 1; $i <= $anz_abt; $i++) {
if (!in_array($i, $existing, true)) {
$stmt->bind_param('i', $i);
$stmt->execute();
}
}
$stmt->close();
http_response_code(201);

View File

@@ -0,0 +1,74 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
// Show all errors except deprecation notices (these come from vendor libraries
// that aren't yet typed for newer PHP versions). Long-term fix: update
// dependencies to versions compatible with your PHP runtime.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
// Validate input
if (!isset($_POST['abt']) || !ctype_digit($_POST['abt'])) {
http_response_code(406);
exit;
}
$abtInput = (int) $_POST['abt'];
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo 'Critical DB Error.';
exit;
}
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
// Fetch existing Abteilungen ordered by name
$abts = db_select($mysqli, $tableAbt, '*', '', [], 'name ASC');
$deleteId = null;
$deleteIndex = null;
foreach ($abts as $ind => $abt) {
if ((int)$abt['name'] === (int)$abtInput) {
$deleteId = (int)$abt['id'];
$deleteIndex = $ind;
break;
}
}
if ($deleteId === null) {
http_response_code(406);
exit;
}
// Delete selected row
db_delete($mysqli, $tableAbt, ['id' => $deleteId]);
// Reindex subsequent rows
for ($i = $deleteIndex + 1; $i < count($abts); $i++) {
db_update(
$mysqli,
$tableAbt,
['name' => (int)$abts[$i]['name'] - 1],
['id' => (int)$abts[$i]['id']]
);
}
http_response_code(201);

View File

@@ -0,0 +1,57 @@
<?php
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo 'Critical DB Error.';
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$input = json_decode(file_get_contents('php://input'), true);
if (!$input || !isset($input['new'])) {
http_response_code(400);
exit;
}
$mysqli->begin_transaction();
try {
$stmt = $mysqli->prepare("
UPDATE $tableTurnerinnenAbt
SET turnerin_index = ?
WHERE turnerin_id = ?
");
foreach (['new', 'old'] as $bucket) {
if (empty($input[$bucket])) continue;
foreach ($input[$bucket] as $row) {
$stmt->bind_param("ii", $row['order_index'], $row['id']);
$stmt->execute();
}
}
$mysqli->commit();
http_response_code(200);
} catch (Throwable $e) {
$mysqli->rollback();
http_response_code(500);
}

View File

@@ -0,0 +1,74 @@
<?php
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_wk_leitung']) || $_SESSION['access_granted_wk_leitung'] !== true || empty($_SESSION['passcodewk_leitung_id']) || intval($_SESSION['passcodewk_leitung_id']) < 0 ) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($dbconnection['success'] !== true){
echo 'Critical DB Error.';
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$turnerinId = (int)$_POST['turnerin_id'];
$abteilung = $_POST['abteilung'];
$geraet = $_POST['geraet'];
// Default to NULL if frontend sends "null"
$abtId = null;
$geraetId = null;
// Resolve Abteilung ID
if ($abteilung !== 'null') {
$stmt = $mysqli->prepare("SELECT id FROM $tableAbt WHERE name = ?");
$stmt->bind_param("s", $abteilung);
$stmt->execute();
if ($row = $stmt->get_result()->fetch_assoc()) {
$abtId = (int)$row['id'];
}
$stmt->close();
}
// Resolve Gerät ID
if ($geraet !== 'null') {
$stmt = $mysqli->prepare("SELECT id FROM $tableGeraete WHERE name = ?");
$stmt->bind_param("s", $geraet);
$stmt->execute();
if ($row = $stmt->get_result()->fetch_assoc()) {
$geraetId = (int)$row['id'];
}
$stmt->close();
}
// Upsert into turnerinnen_abt (turnerin_id is UNIQUE)
$stmt = $mysqli->prepare("
INSERT INTO $tableTurnerinnenAbt (turnerin_id, abteilung_id, geraet_id)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE
abteilung_id = VALUES(abteilung_id),
geraet_id = VALUES(geraet_id)
");
$stmt->bind_param("iii", $turnerinId, $abtId, $geraetId);
$stmt->execute();
$stmt->close();
// Return JSON
http_response_code(200);
echo json_encode([
'success' => true,
'turnerin_id' => $turnerinId,
'abteilung_id' => $abtId,
'geraet_id' => $geraetId
]);

View File

@@ -0,0 +1,204 @@
<?php
/**
* Shared Sidebar Navigation
*
* Include this file after <body> on any intern page.
* Set $currentPage before including, e.g.:
* $currentPage = 'trainer';
* require $baseDir . '/intern/scripts/sidebar/sidebar.php';
*/
$isWKL = $_SESSION['access_granted_wk_leitung'] ?? false;
$isTrainer = $_SESSION['access_granted_trainer'] ?? false;
$isKampfrichter = $_SESSION['access_granted_kampfrichter'] ?? false;
if (!isset($currentPage)) $currentPage = '';
if (isset($_POST['abmelden'])) {
if (session_status() === PHP_SESSION_ACTIVE) {
$_SESSION = array();
session_destroy();
}
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
// SVG Icons (stroke-based, 24x24 viewBox)
$icons = [
'trainer' => '<svg viewBox="0 0 24 24"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>',
'kampfrichter' => '<svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>',
'rechnungen' => '<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>',
'logindata' => '<svg viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>',
'displaycontrol' => '<svg viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>',
'kalender' => '<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>',
'riegeneinteilung' => '<svg viewBox="0 0 24 24"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><rect x="8" y="2" width="8" height="4" rx="1" ry="1"/><line x1="9" y1="12" x2="15" y2="12"/><line x1="9" y1="16" x2="15" y2="16"/></svg>',
'einstellungen' => '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>',
];
if (isset($mysqli) && isset($tableInternUsers)) {
if ($currentPage === 'kampfrichter' && checkIfUserHasSessionId('kampfrichter')):
$userDispId = intval($_SESSION['passcodekampfrichter_id']);
elseif ($currentPage === 'kampfrichter' && checkIfUserHasSessionId('trainer')):
$userDispId = intval($_SESSION['passcodetrainer_id']);
elseif ($isWKL && checkIfUserHasSessionId('wk_leitung')):
$userDispId = intval($_SESSION['passcodewk_leitung_id']);
endif;
$sql = "SELECT `username`, `freigabe` FROM $tableInternUsers WHERE id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $userDispId);
$stmt->execute();
$stmt->bind_result($usernameDB, $freigabenDB);
$stmt->fetch();
$username = $usernameDB ?? '';
$decoded = json_decode($freigabenDB, true);
$freigabenSidebar = is_array($decoded) ? $decoded : [];
$stmt->close();
}
$links = [];
$renderMenu = true;
// Trainer & Kampfrichter are visible to their own role + WKL
if ($isTrainer || $isWKL) {
$links[] = ['key' => 'trainer', 'label' => 'Trainer', 'url' => '/intern/trainer', 'freigaben' => true];
}
if ($isKampfrichter || $isWKL) {
$links[] = ['key' => 'kampfrichter', 'label' => 'Kampfrichter', 'url' => '/intern/kampfrichter', 'freigaben' => true];
}
// WKL-only pages
if ($isWKL) {
$links[] = ['key' => 'rechnungen', 'label' => 'Rechnungen', 'url' => '/intern/wk-leitung/rechnungen', 'freigaben' => false];
$links[] = ['key' => 'logindata', 'label' => 'Benutzerverwaltung', 'url' => '/intern/wk-leitung/logindata', 'freigaben' => false];
$links[] = ['key' => 'displaycontrol', 'label' => 'Displaycontrol', 'url' => '/intern/wk-leitung/displaycontrol', 'freigaben' => false];
//$links[] = ['key' => 'kalender', 'label' => 'Kalender', 'url' => '/intern/wk-leitung/kalender'];
$links[] = ['key' => 'riegeneinteilung', 'label' => 'Riegeneinteilung', 'url' => '/intern/wk-leitung/riegeneinteilung', 'freigaben' => false];
$links[] = ['key' => 'einstellungen', 'label' => 'Einstellungen', 'url' => '/intern/wk-leitung/einstellungen', 'freigaben' => false];
}
function checkIfUserHasSessionId($type) : bool {
if (isset($_SESSION['passcode'.$type.'_id']) && intval(['passcode'.$type.'_id']) > 0) { return true; }
else { return false; }
}
function sidebarRender(string $mode) {
global $isWKL, $isTrainer, $isKampfrichter, $links, $currentPage, $icons, $renderMenu, $username, $freigabenSidebar;
if (!$renderMenu) { return; }
if ($mode === 'button') {
?>
<!-- Sidebar Toggle Button -->
<button class="sidebar-toggle" id="sidebar-toggle" aria-label="Navigation öffnen">
<span></span>
<span></span>
<span></span>
</button>
<?php } elseif ($mode === 'modal') { ?>
<!-- Sidebar Overlay -->
<div class="sidebar-overlay" id="sidebar-overlay"></div>
<!-- Sidebar Panel -->
<nav class="sidebar-nav" id="sidebar-nav">
<div class="sidebar-header">
<h3>Navigation</h3>
<button class="sidebar-close-btn" id="sidebar-close" aria-label="Schliessen">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</div>
<?php if ($isWKL && ($isTrainer || $isKampfrichter || true)): ?>
<div class="sidebar-section-label">Allgemein</div>
<?php endif; ?>
<ul class="sidebar-links">
<?php foreach ($links as $i => $link):
$isCurrentPage = ($currentPage === $link['key']);
$activeClass = $isCurrentPage ? ' active' : '';
$icon = $icons[$link['key']] ?? '';
$freigbenArrayName = 'freigaben' . ucfirst($link['key']);
// Insert section divider before WKL-only links
if ($isWKL && $link['key'] === 'rechnungen' && $i > 0): ?>
</ul>
<div class="sidebar-section-label">WK-Leitung</div>
<ul class="sidebar-links">
<?php endif; ?>
<li>
<a href="<?php echo $link['url']; ?>" class="<?php echo trim($activeClass); ?>">
<?php echo $icon; ?>
<?php echo htmlspecialchars($link['label']); ?>
</a>
</li>
<?php if ($isCurrentPage && $link['freigaben'] === true && isset($freigabenSidebar[$freigbenArrayName]) && count($freigabenSidebar[$freigbenArrayName]) > 1) : ?>
<?php $selectedFreigabe = $_SESSION['selectedFreigabe' . ucfirst($link['key'])] ?? ''; ?>
<li class="sidebar-li-freigaben">
<label class="sidebar-freigaben-label" for="selectTriggerFreigabe">Freigabe</label>
<div class="customSelect" id="selectedOption" data-value="[]">
<button type="button" id="selectTriggerFreigabe" class="selectTrigger" aria-expanded="false">
<span class="selectLabel"><?= $selectedFreigabe ?></span>
<svg class="selectArrow" xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' height="14" width="14">
<path d='M6 9L12 15L18 9' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/>
</svg>
</button>
<ul class="selectOptions">
<?php foreach ($freigabenSidebar[$freigbenArrayName] as $f) :?>
<?php $selected = ($f === $selectedFreigabe) ? 'selected' : '' ?>
<li data-value="<?= htmlspecialchars($f) ?>" class="<?= $selected ?>"><?= htmlspecialchars($f) ?></li>
<?php endforeach; ?>
</ul>
<input type="hidden" name="type" class="selectValue" id="freigabenSidebarSelect" value="">
</div>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
<?php
if (isset($username)) : ?>
<div class="sidebarUsername">Benutzer: <?= $username ?></div>
<?php endif; ?>
<div class="sidebar-footer">
<form method="POST" action="" class="abmelden"><input class="abmeldenbutton" type="submit" href="?logout=1" name="abmelden" value="Abmelden"></form>
</div>
</nav>
<script>
const siteType = '<?= $currentPage ?>';
// Close button binding (inline to avoid race condition with sidebar.js)
document.addEventListener('DOMContentLoaded', function() {
var closeBtn = document.getElementById('sidebar-close');
if (closeBtn) {
closeBtn.addEventListener('click', function() {
document.getElementById('sidebar-nav').classList.remove('open');
document.getElementById('sidebar-overlay').classList.remove('open');
document.getElementById('sidebar-toggle').classList.remove('open');
localStorage.setItem('intern_sidebar_open', 'false');
});
}
});
</script>
<script src="/intern/js/sidebar.js"></script>
<?php
}
}

View File

@@ -0,0 +1,172 @@
<?php
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if ( empty($_SESSION['access_granted_trainer']) || $_SESSION['access_granted_trainer'] !== true || empty($_SESSION['passcodetrainer_id']) || intval($_SESSION['passcodetrainer_id']) < 1 ) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
$type = 'tr';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$ids = isset($_GET['ids']) ? htmlspecialchars(strip_tags(trim($_GET['ids'])), ENT_QUOTES) : '';
$user = intval($_SESSION['passcodetrainer_id']);
$arrayids = array_filter(array_map('trim', explode(',', $ids)));
if (!$arrayids || !is_array($arrayids) || count($arrayids) === 0) {
http_response_code(422);
exit;
}
if ($user <= 0) {
http_response_code(422);
exit;
}
$placeholders = [];
$values = [];
$types = '';
foreach ($arrayids as $id) {
if ($id <= 0) {
http_response_code(422);
exit;
}
$sql = "SELECT bezahlt FROM $tableTurnerinnen WHERE id = ?";
$checkstmt = $mysqli->prepare($sql);
$checkstmt->bind_param("i", $id);
if (!$checkstmt->execute()) {
http_response_code(500);
exit;
}
$checkstmt->bind_result($bezahlt);
$checkstmt->fetch();
$checkstmt->close();
$sql2 = "SELECT COUNT(*) FROM $tableBasketItems WHERE user_id = ? AND item_id = ?";
$checkstmt2 = $mysqli->prepare($sql2); // ✔ use $sql2
$checkstmt2->bind_param("ii", $user, $id);
if (!$checkstmt2->execute()) {
http_response_code(500);
exit;
}
// Bind the result
$checkstmt2->bind_result($countProd);
$checkstmt2->fetch(); // fetch into $countProd
$checkstmt2->close();
if ((isset($bezahlt) && (intval($bezahlt) === 0 || intval($bezahlt) === 1)) && $countProd === 0) {
$placeholders[] = '(?, ?)';
$types .= 'ii'; // assuming user_id and item_id are integers
$values[] = $user;
$values[] = $id;
}
}
if ($values === [] || $placeholders === [] || $types === '') {
http_response_code(406);
exit;
}
$sql = "INSERT INTO `$tableBasketItems` (user_id, item_id) VALUES " . implode(',', $placeholders);
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($types, ...$values);
$success = $stmt->execute();
$stmt->close();
if (!$success) {
http_response_code(500);
exit;
}
// Prepare statements once
$sSql = "SELECT `name`, `vorname`, `programm`
FROM $tableTurnerinnen
WHERE id = ?";
$pSql = "SELECT preis
FROM $tableProgramme
WHERE programm = ? AND aktiv = 1";
$sStmt = $mysqli->prepare($sSql);
$pStmt = $mysqli->prepare($pSql);
foreach ($arrayids as $id) {
// --- Turnerinnen ---
$sStmt->bind_param("i", $id);
if (!$sStmt->execute()) {
http_response_code(500);
exit;
}
$row = $sStmt->get_result()->fetch_assoc();
if (!$row || !isset($row['programm'])) {
http_response_code(500);
exit;
}
// --- Programme ---
$pStmt->bind_param("s", $row['programm']);
if (!$pStmt->execute()) {
http_response_code(500);
exit;
}
$pRow = $pStmt->get_result()->fetch_assoc();
if (!$pRow || !isset($pRow['preis'])) {
http_response_code(500);
exit;
}
// --- Build response ---
$arrayresponse[$id] = [
'turnerinName' => $row['name'],
'turnerinVorname' => $row['vorname'],
'programm' => $row['programm'],
'preis' => $pRow['preis']
];
}
// Close statements once
$sStmt->close();
$pStmt->close();
http_response_code(200);
echo json_encode([
'success' => true,
'message' => 'Zum Warenkorb hinzugefügt',
'arrayData' => $arrayresponse
]);
exit;

View File

@@ -0,0 +1,46 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_trainer']) || $_SESSION['access_granted_trainer'] !== true || empty($_SESSION['passcodetrainer_id']) || intval($_SESSION['passcodetrainer_id']) < 1 ) {
http_response_code(403);
exit;
}
$userId = $_SESSION['passcodetrainer_id'];
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
$type = 'tr';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
// --- Check for existing open order ---
$sql = "SELECT * FROM `$tableOrders` WHERE user_id = ? AND order_status = 0 LIMIT 1";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("i", $userId);
$stmt->execute();
$result = $stmt->get_result();
$result = $result->fetch_assoc();
$stmt->close();
if ($result) {
$_SESSION['order_id'] = $result['order_id'];
$_SESSION['order_preis'] = $result['preis'];
}
echo json_encode(['success' => true, 'result' => $result]);
exit;
?>

View File

@@ -0,0 +1,149 @@
<?php
header('Content-Type: application/json');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
$token = isset($_GET['token']) ? $_GET['token'] : '';
/*if ($token !== 'OOlhSGI8CraW6BFmJbj6JFy4sxrYyZ0UxzzbASLhY1sWm0IgqmBXjqqwtqKSvpVFBSBgOFrXHuQLGQj1pxlxj3rlTt1r7kAAWX67dcP'){
echo json_encode(['success' => false, 'message' => '500 Error - Critical Server Error']);
exit;
}*/
if (empty($_SESSION['access_granted_trainer']) || $_SESSION['access_granted_trainer'] !== true || empty($_SESSION['passcodetrainer_id']) || intval($_SESSION['passcodetrainer_id']) < 1 ) {
http_response_code(403);
exit;
}
function generateInvoiceNumber(): int {
return random_int(10000000, 99999999);
}
$orderType = 'Startgebühr';
function createInvoice(mysqli $conn, $tableOrders, $orderType , $preis, $userId, $jsonIds, $order_status): int
{
$maxRetries = 5;
for ($i = 0; $i < $maxRetries; $i++) {
$invoiceNumber = generateInvoiceNumber();
$stmt = $conn->prepare(
"INSERT INTO `$tableOrders` (order_id, order_type, preis, user_id, item_ids, order_status)
VALUES (?, ?, ?, ?, ?, ?)"
);
$stmt->bind_param(
"isdisi",
$invoiceNumber, $orderType, $preis, $userId, $jsonIds, $order_status
);
if ($stmt->execute()) {
return $invoiceNumber; // SUCCESS
}
// Duplicate key error → retry
if ($conn->errno !== 1062) {
throw new RuntimeException(
"Database error ({$conn->errno}): {$conn->error}"
);
}
}
throw new RuntimeException('Failed to generate unique invoice number');
}
$userId = $_SESSION['passcodetrainer_id'];
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
$type = 'tr';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$sql = "SELECT bi.id AS basket_id, bi.item_id, p.programm AS programm_name, p.preis, bi.id
FROM $tableBasketItems bi
LEFT JOIN $tableTurnerinnen t ON bi.item_id = t.id
LEFT JOIN $tableProgramme p ON p.programm = t.programm
WHERE bi.user_id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("i", $userId);
$stmt->execute();
$result = $stmt->get_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);
if (!$rows || count($rows) < 1) {
http_response_code(422);
exit;
}
$preis = 0;
foreach ($rows as $r) {
$preis += floatval($r['preis']);
$ids[] = strval($r['item_id']);
}
if ($preis < 0) {
echo json_encode(['success' => false, 'message' => 'Negative price']);
exit;
}
$jsonIds = json_encode($ids);
if (json_last_error() !== JSON_ERROR_NONE) {
echo json_encode(['success' => false, 'message' => 'Invalid JSON']);
exit;
}
// --- Check for existing open order ---
$sql = "SELECT order_id FROM `$tableOrders` WHERE user_id = ? AND order_status = 0 LIMIT 1";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("i", $userId);
$stmt->execute();
$stmt->bind_result($order_id);
if ($stmt->fetch()) {
// --- UPDATE existing order ---
$stmt->close();
$sql = "
UPDATE `$tableOrders`
SET preis = ?, item_ids = ?
WHERE order_id = ?
";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("dsi", $preis, $jsonIds, $order_id);
$stmt->execute();
$_SESSION['order_id'] = $order_id;
$_SESSION['order_preis'] = $preis;
} else {
// --- INSERT new order ---
$stmt->close();
$order_status = 0;
$new_id = createInvoice($mysqli, $tableOrders, $orderType, $preis, $userId, $jsonIds, $order_status);
$_SESSION['order_id'] = $new_id;
$_SESSION['order_preis'] = $preis;
}
echo json_encode(['success' => true]);
exit;
?>

View File

@@ -0,0 +1,47 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if ( empty($_SESSION['access_granted_trainer']) || $_SESSION['access_granted_trainer'] !== true || empty($_SESSION['passcodetrainer_id']) || intval($_SESSION['passcodetrainer_id']) < 1 ) {
http_response_code(403);
exit;
}
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
$type = 'tr';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
// --- Get input ---
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
$userId = intval($_SESSION['passcodetrainer_id']);
// --- Validate inputs ---
if ($id < 1) {
http_response_code(422);
exit;
}
// --- Check for existing open order ---
$sql = "DELETE FROM $tableBasketItems WHERE user_id = ? AND item_id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("ii", $userId, $id);
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
http_response_code(200);
exit;
?>

View File

@@ -0,0 +1,83 @@
<?php
header('Content-Type: application/json');
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
$isTrainer =
isset($_SESSION['access_granted_trainer'], $_SESSION['passcodetrainer_id']) &&
$_SESSION['access_granted_trainer'] === true &&
(int)$_SESSION['passcodetrainer_id'] > 0;
if (!$isTrainer) {
echo json_encode(['success' => false]);
http_response_code(403);
exit;
}
if (!isset($_POST['musicId']) || !isset($_POST['turnerinId']) || intval($_POST['musicId']) < 1 || intval($_POST['turnerinId']) < 1) {
echo json_encode(['success' => false]);
http_response_code(422);
exit;
}
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
$type = 'tr';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
http_response_code(500);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$musicId = intval($_POST['musicId']);
$turnerinId = intval($_POST['turnerinId']);
$sql = "UPDATE $tableTurnerinnen SET bodenmusik = ? WHERE id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("ss", $musicId, $turnerinId);
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$stmt->close();
$sql = "SELECT name, vorname FROM $tableTurnerinnen WHERE id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("s", $turnerinId);
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$result = $stmt->get_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
$_SESSION['form_message_type'] = 1;
if (!isset($rows) || !is_array($rows) || count($rows) !== 1) {
$_SESSION['form_message'] = 'Musik aktualisiert';
} else {
$_SESSION['form_message'] = 'Musik für '.$rows[0]['name'].' '.$rows[0]['vorname'].' aktualisiert';
}
$mysqli->close();
echo json_encode(['success' => true]);

View File

@@ -0,0 +1,59 @@
<?php
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
$isTrainer =
isset($_SESSION['access_granted_trainer'], $_SESSION['passcodetrainer_id']) &&
$_SESSION['access_granted_trainer'] === true &&
(int)$_SESSION['passcodetrainer_id'] > 0;
if (!$isTrainer) {
echo json_encode(['success' => false]);
http_response_code(403);
exit;
}
if (!isset($_POST['oldMusicId'])) {
echo json_encode(['success' => false]);
http_response_code(422);
exit;
}
$oldMusicId = intval($_POST['oldMusicId']);
if ($oldMusicId < 1) {
echo json_encode(['success' => true]);
http_response_code(202);
exit;
}
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
$type = 'tr';
$data = include $baseDir . '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
http_response_code(500);
exit;
}
require $baseDir . '/../scripts/db/db-tables.php';
$sql = "DELETE $tableAudiofiles WHERE id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("i", $oldMusicId);
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$stmt->close();
$mysqli->close();
echo json_encode(['success' => true]);
http_response_code(200);
exit;

View File

@@ -0,0 +1,122 @@
<?php
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
if (empty($_SESSION['access_granted_trainer']) || $_SESSION['access_granted_trainer'] !== true || empty($_SESSION['passcodetrainer_id']) || $_SESSION['passcodetrainer_id'] < 1) {
http_response_code(403);
exit;
}
if (!isset($_POST['preis']) || !isset($_POST['name']) || !isset($_POST['vorname']) || !isset($_POST['strasse']) || !isset($_POST['plz']) || !isset($_POST['ort']) || !isset($_POST['hausnummer'])) {
echo json_encode(['success' => false, 'message' => 'Invalid input']);
exit;
}
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
require $baseDir . '/../composer/vendor/autoload.php';
use Sprain\SwissQrBill as QrBill;
// This is an example how to create a typical qr bill:
// - with reference number
// - with known debtor
// - with specified amount
// - with human-readable additional information
// - using your QR-IBAN
//
// Likely the most common use-case in the business world.
// Create a new instance of QrBill, containing default headers with fixed values
$qrBill = QrBill\QrBill::create();
$name = trim((string)($rechnungenVorname ?? '') . ' ' . (string)($rechnungenName ?? ''));
$strasse = (string)($rechnungenStrasse ?? '');
$hausnr = (string)($rechnungenHausnummer ?? '');
$plz = (string)($rechnungenPostleitzahl ?? '');
$ort = (string)($rechnungenOrt ?? '');
$qrBill->setCreditor(
QrBill\DataGroup\Element\StructuredAddress::createWithStreet(
$name,
$strasse,
$hausnr,
$plz,
$ort,
'CH'
)
);
$iban = strtoupper(str_replace(' ', '', (string)($rechnungenIBAN ?? '')));
$qrBill->setCreditorInformation(
QrBill\DataGroup\Element\CreditorInformation::create($iban)
);
// Add debtor information
// Who has to pay the invoice? This part is optional.
$qrBill->setUltimateDebtor(
QrBill\DataGroup\Element\StructuredAddress::createWithStreet(
$_POST['vorname'] . ' ' . $_POST['name'],
$_POST['strasse'],
$_POST['hausnummer'],
$_POST['plz'],
$_POST['ort'],
'CH'
)
);
// Add payment amount information
// What amount is to be paid?
$qrBill->setPaymentAmountInformation(
QrBill\DataGroup\Element\PaymentAmountInformation::create(
'CHF',
$totalPreis
)
);
// Add payment reference
// This is what you will need to identify incoming payments.
$qrBill->setPaymentReference(
QrBill\DataGroup\Element\PaymentReference::create(
QrBill\DataGroup\Element\PaymentReference::TYPE_SCOR,
QrBill\Reference\RfCreditorReferenceGenerator::generate($dbresult['order_id'])
)
);
$month = date('m');
if ($month < 6){
$jahr = date('Y');
} else {
$jahr = date('Y') + 1;
}
$referenz = "Startgebühren ". $wkName. " ".$jahr;
// Optionally, add some human-readable information about what the bill is for.
$qrBill->setAdditionalInformation(
QrBill\DataGroup\Element\AdditionalInformation::create(
$referenz
)
);
// Now get the QR code image and save it as a file.
/*try {
$qrBill->getQrCode()->writeFile(__DIR__ . '/qrneu.png');
$qrBill->getQrCode()->writeFile(__DIR__ . '/qrneu.svg');
} catch (\Throwable $e) {
foreach ($qrBill->getViolations() as $violation) {
print $violation->getMessage()."\n";
}
// Also print exception message when available
error_log('QR bill error: ' . $e->getMessage());
exit;
}*/
// Next: Output full payment parts, depending on the format you want to use:
//
// - FpdfOutput/fpdf-example.php
// - HtmlOutput/html-example.php
// - TcPdfOutput/tcpdf-example.php

View File

@@ -0,0 +1,424 @@
<?php
use Sprain\SwissQrBill\PaymentPart\Output\DisplayOptions;
use Sprain\SwissQrBill\PaymentPart\Output\TcPdfOutput\TcPdfOutput;
use TCPDF;
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
require $baseDir . '/../composer/vendor/autoload.php';
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
// Show all errors except deprecation notices (these come from vendor libraries
// that aren't yet typed for newer PHP versions). Long-term fix: update
// dependencies to versions compatible with your PHP runtime.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
// Add a higher memory limit
ini_set('memory_limit', '256M'); // Start with 256M, increase if needed
session_start();
if (empty($_SESSION['access_granted_trainer']) || $_SESSION['access_granted_trainer'] !== true || empty($_SESSION['passcodetrainer_id']) || $_SESSION['passcodetrainer_id'] < 1) {
http_response_code(403);
header("Location: /intern/trainer");
exit;
}
if (!isset($_SESSION['order_id']) || !isset($_SESSION['order_preis'])) {
http_response_code(403);
exit;
}
if (!isset($_POST['order_id']) || !isset($_POST['preis']) || !isset($_POST['name']) || !isset($_POST['vorname']) || !isset($_POST['strasse']) || !isset($_POST['plz']) || !isset($_POST['ort'])) {
http_response_code(422);
exit;
}
if (intval($_SESSION['order_id']) !== intval($_POST['order_id']) || intval($_SESSION['order_preis']) !== intval($_POST['preis'])) {
http_response_code(401);
exit;
}
$type = 'tr';
$data = include $baseDir. '/../scripts/db/db-verbindung-script.php';
if ($data['success'] === false){
echo json_encode(['success' => false, 'message' => $data['message']]);
exit;
}
require $baseDir. '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$dbresult = db_select($mysqli, $tableOrders, '*', 'order_id = ?', [$_POST['order_id']]);
if ($dbresult === false || count($dbresult) === 0) {
echo json_encode(['success' => false, 'message' => 'Order not found']);
exit;
} elseif (count($dbresult) > 1) {
echo json_encode(['success' => false, 'message' => 'Error: Multiple orders found with the same ID']);
exit;
}
$wkName = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['wkName']);
$rechnungenName = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rechnungenName']);
$rechnungenVorname = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rechnungenVorname']);
$rechnungenStrasse = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rechnungenStrasse']);
$rechnungenHausnummer = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rechnungenHausnummer']);
$rechnungenPostleitzahl = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rechnungenPostleitzahl']);
$rechnungenOrt = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rechnungenOrt']);
$rechnungenIBAN = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rechnungenIBAN']);
$linkWebseite = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['linkWebseite']);
$dbresult = $dbresult[0];
$orderStatus = (floatval($_SESSION['order_preis']) === 0.0 && !isset($_POST['postversand'])) ? 2 : 1 ;
$orderId = intval($_POST['order_id']);
$current_year = date('Y');
$monat = date('n');
if ($monat > 6) $current_year++;
class MYPDF extends TCPDF
{
public $columns;
public $headerBottomY = 0;
public $firstPageDone = false; // track first page
public $printfooter;
public function Header()
{
// Logo always
$image_file = $_SERVER['DOCUMENT_ROOT'] . '/intern/img/logo-normal.png';
$this->Image($image_file, 180, 15, 15);
// Table header only for subsequent pages
if ($this->firstPageDone && !empty($this->columns)) {
// Use same top margin as table
$this->SetY(35); // or another fixed Y
$this->SetX(15);
$this->SetFont('GoogleSansFlex-Regular', '', 11);
$this->setCellPaddings(2, 0, 2, 0);
foreach ($this->columns as $c) {
$this->Cell($c['max_width'], 10, $c['header'], 0, 0, 'L');
}
$this->Ln();
$this->headerBottomY = $this->GetY();
$this->SetLineWidth(0.6);
$this->Line(15, $this->GetY(), 210 - 15, $this->GetY());
$this->SetLineWidth(0.2);
}
}
public function Footer()
{
}
}
// --- Create PDF ---
$pdf = new MYPDF('P', 'mm', 'A4', true, 'UTF-8', false);
$pdf->current_year = (date('n') > 6) ? date('Y') + 1 : date('Y');
$pdf->wkp_name = $rechnungenVorname . ' ' . $rechnungenName;
$pdf->wkp_adresse = $rechnungenStrasse . ' ' . $rechnungenHausnummer;
$pdf->wkp_plz_ort = $rechnungenPostleitzahl . ' ' . $rechnungenOrt;
$pdf->wkp_url = $linkWebseite;
$pdf->wk_name = $wkName;
$pdf->pers_name = $_POST['vorname'] . ' ' . $_POST['name'];
$pdf->pers_adresse = $_POST['strasse'] . ' ' . $_POST['hausnummer'];
$pdf->pers_plz_ort = $_POST['plz'] . ' ' . $_POST['ort'];
$pdf->printfooter = true;
// Mark first page done so Header() prints table headers on subsequent pages
$pdf->firstPageDone = false;
$pdf->setCellPaddings(2, 0, 2, 0);
$pdf->SetMargins(15, 35, 15);
// Fonts
$pdf->AddFont('GoogleSansFlex9pt-Bold', '', $_SERVER['DOCUMENT_ROOT'] . '/../private-files/tcpdf-fonts/googlesansflex_9ptb.php');
$pdf->AddFont('GoogleSansFlex-Regular', '', $_SERVER['DOCUMENT_ROOT'] . '/../private-files/tcpdf-fonts/gsf.php');
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('WKVS');
$pdf->SetAutoPageBreak(TRUE, 10);
$pdf->SetFont('GoogleSansFlex-Regular', '', 11);
// --- Add a page ---
$pdf->AddPage();
// --- Sender block (left) ---
$pdf->SetX(15);
$pdf->Cell(0, 0, $pdf->wkp_name, 0, 1);
$pdf->Cell(0, 0, $pdf->wkp_adresse, 0, 1);
$pdf->Cell(0, 0, $pdf->wkp_plz_ort, 0, 1);
$pdf->Ln(7);
$pdf->Cell(0, 0, $pdf->wkp_url, 0, 1);
// --- Recipient block (right / window) ---
$x = 110; // X coordinate for right window
$y = 50; // Y coordinate
$w = 80; // Width of recipient block
$address = implode("\n", [
$pdf->pers_name,
$pdf->pers_adresse,
$pdf->pers_plz_ort
]);
$pdf->MultiCell($w, 5, $address, 0, 'L', false, 1, $x, $y, true);
date_default_timezone_set('UTC');
// --- Invoice title ---
$pdf->Ln(20); // space below recipient
$pdf->SetFont('GoogleSansFlex9pt-Bold', '', 15);
$pdf->Cell(0, 10, 'Startgebührenrechnung ' . $pdf->wk_name . ' ' . $pdf->current_year, 0, 1, 'L');
$pdf->SetFont('GoogleSansFlex-Regular', '', 10);
$pdf->Cell(0, 9, "Rechnungsnummer: " . $orderId, 0, 1, 'L');
$pdf->SetFont('GoogleSansFlex-Regular', '', 7);
$pdf->Cell(0, 0, "Ausstellungsdatum: " . date("d.m.y"), 0, 1, 'L');
$pdf->Ln(10); // space below title
$pdf->SetFont('GoogleSansFlex9pt-Bold', '', 13);
//$turnerinnnenIds = [];
$turnerinnnenIds = explode(',', str_replace(['[', ']','"'], '', $dbresult['item_ids']));
$columns = ['name' => ['header' => 'Name'],
'programm' => ['header' => 'Programm'],
'verein' => ['header' => 'Verein'],
'preis' => ['header' => 'Startgebühr']];
foreach ($columns as $key => $column){
$columns[$key]['max_width'] = $pdf->GetStringWidth($column['header']);
}
$totalPreis = 0.00;
$dbdata = [];
foreach ($turnerinnnenIds as $singleid){
$newdbresult = db_select($mysqli, $tableTurnerinnen, 'name, vorname, programm, verein', 'id = ?', [$singleid]);
if ($newdbresult && count($newdbresult) === 1){
$dbdata[$singleid] = $newdbresult;
$pdf->SetFont('', '', 10);
$text = 'Startgebühr '.$newdbresult[0]['name'].' '.$newdbresult[0]['vorname'];
if ($pdf->GetStringWidth($text) > $columns['name']['max_width'] ?? 0){
$columns['name']['max_width'] = $pdf->GetStringWidth($text);
}
if ($pdf->GetStringWidth($newdbresult[0]['programm']) > $columns['programm']['max_width'] ?? 0){
$columns['programm']['max_width'] = $pdf->GetStringWidth($newdbresult[0]['programm']);
}
if ($pdf->GetStringWidth($newdbresult[0]['verein']) > $columns['verein']['max_width'] ?? 0){
$columns['verein']['max_width'] = $pdf->GetStringWidth($newdbresult[0]['verein']);
}
if (isset($newdbresult[0]['programm'])){
$dbpreis = db_select($mysqli, $tableProgramme, 'preis', 'programm = ?', [$newdbresult[0]['programm']]);
if ($newdbresult && count($newdbresult) === 1 && isset($dbpreis[0]['preis'])){
$preis = $dbpreis[0]['preis'];
$totalPreis += floatval($dbpreis[0]['preis']);
} else {
$preis = 'ERROR';
}
if ($pdf->GetStringWidth('CHF '.$preis) > $columns['preis']['max_width'] ?? 0){
$columns['preis']['max_width'] = $pdf->GetStringWidth('CHF '.$preis);
}
}
}
}
foreach ($columns as $key => $column){
$columns[$key]['max_width'] += 2; // Add some padding
}
$maxWidth = 210 - 30; // A4 width minus margins
$totalColumnWidth = 0;
foreach ($columns as $column){
$totalColumnWidth += $column['max_width'];
}
if ($totalColumnWidth < $maxWidth){
$scalingFactor = $maxWidth / $totalColumnWidth;
foreach ($columns as $key => $column){
$columns[$key]['max_width'] = $column['max_width'] * $scalingFactor;
}
}
foreach ($columns as $c) {
$pdf->Cell($c['max_width'], 10, $c['header'], 0, 0, 'L');
}
$pdf->Ln();
$pdf->SetLineWidth(0.6);
$pdf->Line(15, $pdf->GetY(), 210 - 15, $pdf->GetY());
$pdf->SetLineWidth(0.2);
$pdf->headerBottomY = $pdf->GetY();
// --- Set top margin for table below title ---
// Mark first page done so Header() prints table headers on subsequent pages
$pdf->firstPageDone = true;
$pdf->SetFont('GoogleSansFlex-Regular', '', 11);
$pdf->columns = $columns;
$margin_top = $pdf->headerBottomY;
$pdf->SetMargins(15, 45, 15); // +5 mm padding below header
$pdf->SetY($margin_top); // Move cursor below header manually
foreach ($dbdata as $singleid => $newdbresult){
$pdf->SetFont('', '', 10);
$text = 'Startgebühr '.$newdbresult[0]['name'].' '.$newdbresult[0]['vorname'];
$pdf->Cell($columns['name']['max_width'], 10, $text, 0, 0, 'L');
$pdf->Cell($columns['programm']['max_width'], 10, $newdbresult[0]['programm'], 0, 0, 'L');
$pdf->Cell($columns['verein']['max_width'], 10, $newdbresult[0]['verein'], 0, 0, 'L');
$pdf->SetFillColor(100, 100, 100);
if (isset($newdbresult[0]['programm'])){
$dbpreis = db_select($mysqli, $tableProgramme, 'preis', 'programm = ?', [$newdbresult[0]['programm']]);
if ($newdbresult && count($newdbresult) === 1 && isset($dbpreis[0]['preis'])){
$preis = $dbpreis[0]['preis'];
} else {
$preis = 'ERROR';
}
$pdf->Cell($columns['preis']['max_width'], 10, 'CHF ' . $preis, 0, 1, 'C');
}
$pdf->SetDrawColor(100, 100, 100);
$pdf->Line(15, $pdf->getY(), 210 - 15, $pdf->getY());
$pdf->SetDrawColor(0, 0, 0);
}
/*
if (isset($_POST['postversand'])) {
$pdf->SetFont('', '', 10);
$text = 'Postversand der Rechnung durch WKVS';
$pdf->Cell($columns['name']['max_width'], 10, $text, 0, 0, 'L');
$pdf->Cell($columns['programm']['max_width'], 10, '', 0, 0, 'L');
$pdf->Cell($columns['verein']['max_width'], 10, '', 0, 0, 'L');
$pdf->SetFillColor(100, 100, 100);
$pdf->Cell($columns['preis']['max_width'], 10, 'CHF 2.50', 0, 1, 'C');
$pdf->SetDrawColor(100, 100, 100);
$pdf->Line(15, $pdf->getY(), 210 - 15, $pdf->getY());
$pdf->SetDrawColor(0, 0, 0);
$totalPreis += 2.5;
}
*/
if ($totalPreis !== 0) {
require __DIR__ . '/ajax-neu_qr_rechnung.php';
}
$pdf->Ln(3);
$pdf->SetFont('GoogleSansFlex9pt-Bold', '', 10);
$pdf->Cell(100, 10, "Gesamt:", 0, 0, 'L');
$pdf->SetX($columns['name']['max_width'] + $columns['programm']['max_width'] + $columns['verein']['max_width'] + 15);
$pdf->Cell($columns['preis']['max_width'], 10, 'CHF ' . number_format($totalPreis, 2), 0, 1, 'C');
$pdf->SetFont('GoogleSansFlex-Regular', '', 10);
if ($totalPreis !== 0) {
$pdf->Ln(10);
$pdf->SetTextColor(90, 103, 39);
$pdf->MultiCell(0, 8, 'Diese Rechnung wurde als bezahlt eigetragen, da der Betrag 0 CHF beträgt', 0, 'L');
$pdf->SetTextColor(0, 0, 0);
} else {
// 3. Create a full payment part for TcPDF
$output = new TcPdfOutput($qrBill, 'de', $pdf);
// 4. Optional, set layout options
if (class_exists(\Sprain\SwissQrBill\PaymentPart\Output\DisplayOptions::class)) {
$displayOptions = new \Sprain\SwissQrBill\PaymentPart\Output\DisplayOptions();
$displayOptions
->setPrintable(false) // true to remove lines for printing on a perforated stationery
->setDisplayTextDownArrows(false) // true to show arrows next to separation text, if shown
->setDisplayScissors(false) // true to show scissors instead of separation text
->setPositionScissorsAtBottom(false) // true to place scissors at the bottom, if shown
;
// 5. Generate the output, applying display options when supported
if (method_exists($output, 'setDisplayOptions')) {
$output->setDisplayOptions($displayOptions);
}
} else {
// DisplayOptions class is not available in the installed package version.
// We proceed without custom display options.
}
// Generate the payment part (always call)
if ($pdf->getY() > 297 - 120) {
$pdf->firstPageDone = false;
$pdf->printfooter = false;
$pdf->addPage();
}
$output->getPaymentPart();
}
if (isset($_SESSION['order_id'])) unset($_SESSION['order_id']);
if (isset($_SESSION['order_preis'])) unset($_SESSION['order_preis']);
$filename = 'Rechnung Startgebuehren '.$wkName.' '.$current_year.' '.date('YmdHis').'.pdf';
$pdf->SetTitle($filename);
$savePath = $baseDir . '/../private-files/rechnungen/' . $orderId . '.pdf';
// Save PDF to disk
$pdf->Output($savePath, 'F');
$sql = "UPDATE $tableOrders SET order_status = ? WHERE order_id = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("ii", $orderStatus, $orderId);
$stmt->execute();
$stmt->close();
// 2. DELETE basket items
db_delete($mysqli, $tableBasketItems, ['user_id' => intval($_SESSION['passcodetrainer_id'])]);
$mysqli->close();
// Send headers manually
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . $dirFileName . '"');
header('Content-Length: ' . filesize($savePath));
// Send file contents
readfile($savePath);
exit;

View File

@@ -0,0 +1,13 @@
const texts = document.querySelectorAll('.textWelcomeScreen');
texts.forEach(text => {
const characters = text.textContent.split('');
text.textContent = '';
characters.forEach((char, index) => {
const span = document.createElement('span');
span.textContent = char;
span.style.animationDelay = `${index * 0.1}s`;
text.appendChild(span);
});
});

View File

@@ -0,0 +1,24 @@
<link rel="stylesheet" href="/intern/css/wkvs.css">
<div class="welcomeScreen">
<div class="innerWelcomeScreen">
<p class="textWelcomeScreen title">WKVS</p>
<p class="textWelcomeScreen text">Kunstturnen</p>
</div>
</div>
<script>
const texts = document.querySelectorAll('.textWelcomeScreen');
texts.forEach(text => {
const characters = text.textContent.split('');
text.textContent = '';
characters.forEach((char, index) => {
const span = document.createElement('span');
span.textContent = char;
span.style.animationDelay = `${index * 0.1}s`;
text.appendChild(span);
});
});
</script>