Semi-stable version with old variable names

This commit is contained in:
Fabio Herzig
2026-07-16 18:43:30 +02:00
parent 3731183654
commit c8e7ce9174
165 changed files with 25654 additions and 9728 deletions
@@ -1,9 +1,5 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
header('Content-Type: application/json');
if (!isset($baseDir)) {
@@ -31,10 +27,14 @@ require $baseDir . '/../scripts/db/db-tables.php';
$allowedTypes = [
'wkName',
'displayCTextLogo',
'displayCTextWKName',
'displayColourLogo',
'displayTextColourLogo',
'displayColorScoringBg',
'displayColorScoringBgSoft',
'displayColorScoringShadowColor',
'displayColorScoringBorderColor',
'displayColorScoringPanel',
'displayColorScoringPanelSoft',
'displayColorScoringPanelText',
@@ -53,8 +53,15 @@ $allowedTypes = [
'maxLengthMusic',
'linkWebseite',
'rangNote',
'orderBestRang'
'orderBestRang',
'rechnungenPostversand',
'rechnungenPostversandKosten',
'personEinzahl',
'personMehrzahl',
'rankLivePublic',
'riegeneinteilungPublic'
];
$type = $_POST['type'] ? trim($_POST['type']) : '';
if (!in_array($type, $allowedTypes)) {
@@ -16,7 +16,6 @@ verify_csrf();
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
@@ -25,20 +24,24 @@ if ($dbconnection['success'] !== true){
exit;
}
require_once $baseDir . '/../scripts/cache/cache-creators/regenerate-display-dependencies-cache.php';
$action = $_POST['action'] ?? '';
if ($action === 'add') {
$name = trim($_POST['name'] ?? '');
$start_index = intval($_POST['start_index'] ?? 0);
$color = trim($_POST['color'] ?? '#424242');
$audiofile = intval($_POST['audiofile'] ?? 0);
$audiofile_max_duration = (int) $_POST['audiofileMaxDuration'] ?? 0;
if (!$name) {
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);
$stmt = $mysqli->prepare("INSERT INTO $tableGeraete (`name`, `start_index`, `color_kampfrichter`, `audiofile`, `audiofile_max_duration`) VALUES (?, ?, ?, ?, ?)");
$stmt->bind_param("sisii", $name, $start_index, $color, $audiofile, $audiofile_max_duration);
$success = $stmt->execute();
$new_id = $mysqli->insert_id;
$stmt->close();
@@ -49,14 +52,17 @@ if ($action === 'add') {
echo json_encode(['success' => false, 'message' => 'Fehler beim Hinzufügen.']);
}
generateIntersectCache($mysqli, $baseDir);
} elseif ($action === 'update') {
$id = intval($_POST['id'] ?? 0);
$field = $_POST['field'] ?? '';
$value = $_POST['value'] ?? '';
$audiofile = intval($_POST['audiofile'] ?? 0);
$allowedFields = ['name', 'start_index', 'color_kampfrichter'];
$allowedFields = ['name', 'start_index', 'color_kampfrichter', 'audiofile', 'audiofile_max_duration'];
if ($id > 0 && in_array($field, $allowedFields)) {
if ($field === 'start_index') {
if ($field === 'start_index' || $field === 'audiofile' || $field === 'audiofile_max_duration') {
$value = intval($value);
}
@@ -80,6 +86,8 @@ if ($action === 'add') {
echo json_encode(['success' => false, 'message' => 'Invalid ID.']);
}
generateIntersectCache($mysqli, $baseDir);
} else {
echo json_encode(['success' => false, 'message' => 'Action not found.']);
}
@@ -1,4 +1,5 @@
<?php
ini_set("display_errors",1);
header('Content-Type: application/json');
if (!isset($baseDir)) {
@@ -16,6 +17,8 @@ verify_csrf();
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.php';
require $baseDir . '/../scripts/string-calculator/string-calculator-functions.php';
$type = 'wkl';
$dbconnection = require $baseDir . '/../scripts/db/db-verbindung-script.php';
@@ -25,6 +28,11 @@ if ($dbconnection['success'] !== true){
exit;
}
require_once $baseDir . '/../scripts/cache/cache-creators/regenerate-display-dependencies-cache.php';
require_once $baseDir . '/../scripts/cache/cache-creators/regenerate-noten-cache.php';
$recalculateJSONs = false;
$action = $_POST['action'] ?? '';
@@ -77,6 +85,8 @@ if ($action === 'add') {
$recalculateJSONs = true;
if ($success) {
regenerate_noten_cache($mysqli, $tableNotenBezeichnungen, $baseDir);
generateIntersectCache($mysqli, $baseDir);
if (!$recalculateJSONs) { echo json_encode(['success' => true, 'id' => $new_id]); }
} else {
echo json_encode(['success' => false, 'message' => 'Fehler beim Hinzufügen.']);
@@ -88,7 +98,7 @@ if ($action === 'add') {
$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'];
$allowedFields = ['name', 'type', 'berechnung', 'pro_geraet', 'geraete_json', 'anzahl_laeufe_json', 'default_value', 'min_value', 'max_value', 'zeige_auf_rangliste', 'nullstellen', 'display_string', 'groesse_auf_rangliste'];
if ($id > 0 && in_array($field, $allowedFields)) {
if ($field === 'pro_geraet') {
$value = intval($value);
@@ -100,6 +110,8 @@ if ($action === 'add') {
$updated = db_update($mysqli, $tableNotenBezeichnungen, [$field => $value], ['id' => $id]);
if ($updated !== false) {
regenerate_noten_cache($mysqli, $tableNotenBezeichnungen, $baseDir);
generateIntersectCache($mysqli, $baseDir);
if (!$recalculateJSONs) { echo json_encode(['success' => true]); }
} else {
echo json_encode(['success' => false, 'message' => 'DB Update failed.']);
@@ -115,6 +127,8 @@ if ($action === 'add') {
if ($id > 0) {
db_delete($mysqli, $tableNotenBezeichnungen, ['id' => $id]);
regenerate_noten_cache($mysqli, $tableNotenBezeichnungen, $baseDir);
generateIntersectCache($mysqli, $baseDir);
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'message' => 'Invalid ID.']);
@@ -143,7 +157,6 @@ if ($recalculateJSONs) {
exit;
}
require $baseDir . "/../scripts/string-calculator/string-calculator-functions.php";
$notenRechner = new NotenRechner();
// 1. Build the direct map
@@ -151,15 +164,23 @@ if ($recalculateJSONs) {
$dependencyMap = [];
foreach ($berechnungen as $calc) {
$neededIdsArray = $notenRechner->getBenoetigteIdsComplex($calc['berechnung']);
$neededIdsArrayWithRun = $notenRechner->getBenoetigteIdsComplexWithRun($calc['berechnung']);
if (empty($neededIdsArray)) {
if (empty($neededIdsArrayWithRun) || count($neededIdsArrayWithRun) < 2) {
continue;
}
$calcId = (int)$calc['id'];
foreach ($neededIdsArray as $needed) {
$neededIdsArray = $neededIdsArrayWithRun;
unset($neededIdsArray['targetRun']);
unset($neededIdsArray['targetGeraet']);
$targetRunId = $neededIdsArrayWithRun['targetRun'];
$target_geraet_id = $neededIdsArrayWithRun['targetGeraet'];
foreach ($neededIdsArray as $key => $needed) {
$nId = (int)$needed['noteId'];
@@ -167,14 +188,14 @@ if ($recalculateJSONs) {
$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;
$nodeKey = $calcId . '|' . $gId . '|' . $targetRunId . '|' . $target_geraet_id; // e.g., "10|S|R2" or "12|3|RA"
if (!isset($dependencyMap[$nId])) {
$dependencyMap[$nId] = [];
}
// Store it as the "little array" you requested: [DependentCalcId, GeraetId]
$dependencyMap[$nId][$nodeKey] = [$calcId, $gId];
$dependencyMap[$nId][$nodeKey] = [$calcId, $gId, [$targetRunId, $target_geraet_id]];
}
}
@@ -0,0 +1,41 @@
<?php
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require_once $baseDir . '/../scripts/session_functions.php';
ini_wkvs_session();
check_user_permission('wk_leitung');
verify_csrf();
if (!isset($_POST['css_content'])) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Missing css_content parameter.']);
exit;
}
$css_content = $_POST['css_content'] ?? '';
if (strlen($css_content) > 200000) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'File size too large.']);
exit;
}
if (preg_match('/javascript:/i', $css_content) || preg_match('/<script/i', $css_content)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Invalid characters detected.']);
exit;
}
file_put_contents($baseDir . '/intern/css/user.css', $css_content);
http_response_code(200);
echo json_encode(['success' => true, 'message' => 'CSS saved successfully.']);
exit;
@@ -0,0 +1,87 @@
<?php
header('Content-Type: application/json');
if (!isset($baseDir)) {
$baseDir = $_SERVER['DOCUMENT_ROOT'];
}
require_once $baseDir . '/../scripts/session_functions.php';
ini_wkvs_session();
check_user_permission('wk_leitung');
verify_csrf();
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/db/db-tables.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'] ?? '');
$has_endtime = intval($_POST['has_endtime'] ?? 0);
$index = intval($_POST['index'] ?? 0);
if (!$name) {
echo json_encode(['success' => false, 'message' => 'Name ist erforderlich.']);
exit;
}
$stmt = $mysqli->prepare("INSERT INTO $tableZeitplanTypes (`name`, `has_endtime`, `display_index`) VALUES (?, ?, ?)");
$stmt->bind_param("sii", $name, $has_endtime, $index);
$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'] ?? '';
$audiofile = intval($_POST['audiofile'] ?? 0);
$allowedFields = ['name', 'has_endtime', 'display_index'];
if ($id > 0 && in_array($field, $allowedFields)) {
if ($field === 'display_index') {
$value = intval($value);
}
$updated = db_update($mysqli, $tableZeitplanTypes, [$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, $tableZeitplanTypes, ['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.']);
}
@@ -0,0 +1,111 @@
<?php
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
require_once $baseDir . '/../scripts/session_functions.php';
ini_wkvs_session();
check_user_permission('wk_leitung');
verify_csrf();
$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';
require $baseDir . '/../scripts/db/db-functions.php';
try {
$mysqli->set_charset("utf8mb4");
// 4. Fetch all rows ordered by ID so the layout hierarchy is preserved
$sql = "SELECT * FROM `$tableNotenBezeichnungen` ORDER BY `id` ASC";
$result = $mysqli->query($sql);
$exportData = [];
while ($row = $result->fetch_assoc()) {
$presetItem = [];
foreach ($row as $columnName => $value) {
if ($columnName === 'berechnung_json') {
continue;
}
if ($value === null) {
$presetItem[$columnName] = null;
} elseif (is_numeric($value)) {
$presetItem[$columnName] = (strpos($value, '.') !== false) ? (float)$value : (int)$value;
} else {
$presetItem[$columnName] = $value;
}
}
$exportDataDisc[] = $presetItem;
}
$result->free();
$geraete = db_select($mysqli, $tableGeraete, '*', '', [], 'start_index ASC');
$programme = db_select($mysqli, $tableProgramme, '*', '', [], 'id ASC');
$zeitplanTypen = db_select($mysqli, $tableZeitplanTypes, '*', '', [], 'id ASC');
$rangNote = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['rangNote']);
$wkName = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['wkName']);
$orderBestRang = db_get_var($mysqli, "SELECT `value` FROM $tableVar WHERE `name` = ?", ['orderBestRang']);
$personEinzahl = db_get_variable($mysqli, $tableVar, ['personEinzahl']);
if ($personEinzahl === null) $personEinzahl = 'Person';
$personMehrzahl = db_get_variable($mysqli, $tableVar, ['personMehrzahl']);
if ($personMehrzahl === null) $personMehrzahl = 'Personen';
$mysqli->close();
$exportData = [
'metadata' => [
'erstellt_am' => date("d.m.Y H:i"),
'ersteller' => $_SERVER['HTTP_HOST'],
'erstellt_mit' => 'WKVS Auto-Export',
'wkvs_json_version' => '1.0.0',
'titel' => 'WKVS Preset ' . $wkName . ' (V 1.0.0)'
],
'noten' => $exportDataDisc,
'disziplinen' => $geraete,
'zeitplan_typen' => $zeitplanTypen,
'rang_konfiguration' => [
'rang_note_id' => $rangNote,
'order_best_rang' => $orderBestRang
],
"leistungsklassen" => $programme,
"bezeichnungen" =>[
"singular" => $personEinzahl,
"plural"=> $personMehrzahl
]
];
$jsonOutput = json_encode($exportData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
// 6. Force Browser File Download
$fileName = 'WKVS-preset-config-' . date('Y-m-d_H-i') . '.json';
header('Content-Type: application/json; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . strlen($jsonOutput));
echo $jsonOutput;
exit;
} catch (mysqli_sql_exception $e) {
http_response_code(500);
echo "Database export failed";
}
@@ -0,0 +1,350 @@
<?php
ini_set("display_errors",1);
if (!isset($baseDir)) $baseDir = $_SERVER['DOCUMENT_ROOT'];
require_once $baseDir . '/../scripts/session_functions.php';
ini_wkvs_session();
check_user_permission('wk_leitung');
verify_csrf();
if (!isset($_FILES['configFile']) || $_FILES['configFile']['error'] !== UPLOAD_ERR_OK) {
echo json_encode([
'success' => false,
'message' => 'Keine Config-Datei ausgewählt'
]);
exit;
}
$wkvsJSONVersion = '1.0.0';
$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';
require $baseDir . '/../scripts/db/db-functions.php';
require $baseDir . '/../scripts/string-calculator/string-calculator-functions.php';
$saveDir = '/../private-files/config-uploads/';
$uploadDir = $baseDir . $saveDir;
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$tmpPath = $_FILES['configFile']['tmp_name'];
$originalName = $_FILES['configFile']['name'];
$extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
$allowedExt = ['json'];
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 = ['application/json'];
if (!in_array($mimeType, $allowedMime, true)) {
echo json_encode(['success' => false, 'message' => 'Dateiinhalt ist kein gültiges JSON']);
http_response_code(422);
exit;
}
$filename = date("Y_m_d_H_i_s") . '-wkvs-config.json';
$destination = $uploadDir . $filename;
if (!move_uploaded_file($tmpPath, $destination)) {
http_response_code(500);
exit;
}
$JSONcontent = file_get_contents($destination);
$content = json_decode($JSONcontent, true);
if (json_last_error() !== JSON_ERROR_NONE) {
die("Invalid JSON layout.");
}
if (!isset($content['metadata']['wkvs_json_version']) || $content['metadata']['wkvs_json_version'] !== $wkvsJSONVersion) {
echo json_encode(['success' => false, 'message' => 'Inkompatible Datei-Version. (V ' . $wkvsJSONVersion . ' benötigt'. (isset($content['metadata']['wkvs_json_version']) ? ", benutzte Datei-Version: V " . $content['metadata']['wkvs_json_version'] : '') . ')' ]);
unlink($destination);
http_response_code(422);
exit;
}
if (!isset($content['noten']) || !is_array($content['noten']) || !isset($content['disziplinen']) || !is_array($content['disziplinen'])) {
echo json_encode(['success' => false, 'message' => 'Ungültige JSON-Struktur']);
unlink($destination);
http_response_code(422);
exit;
}
$content['added_timestamp'] = date("Y-m-d H:i:s");
file_put_contents($destination, json_encode($content));
$allowedColumns = [
'noten' => [
'id', 'name', 'default_value', 'type', 'berechnung', 'berechnung_json',
'max_value', 'min_value', 'pro_geraet', 'anzahl_laeufe_json', 'geraete_json',
'nullstellen', 'display_string'
],
'disziplinen' => ['id', 'name', 'start_index', 'color_kampfrichter', 'audiofile'],
'zeitplan_typen' => ['id', 'name', 'has_endtime', 'display_index'],
'leistungsklassen' => ['id', 'programm', 'order_index', 'preis', 'aktiv']
];
$tableTable = [
'noten' => $tableNotenBezeichnungen,
'disziplinen' => $tableGeraete,
'zeitplan_typen' => $tableZeitplanTypes,
'leistungsklassen' => $tableProgramme
];
$successCount = 0;
try {
$mysqli->begin_transaction();
foreach ($allowedColumns as $type => $columns) {
$tableName = "`" . $tableTable[$type] . "`";
$mysqli->query("DELETE FROM " . $tableName);
$columnsSql = implode(', ', array_map(fn($col) => "`$col`", $columns));
$placeholdersSql = implode(', ', array_fill(0, count($columns), '?'));
$sql = "INSERT INTO " . $tableName . " ($columnsSql)
VALUES ($placeholdersSql)";
$typesString = str_repeat('s', count($columns));
$stmt = $mysqli->prepare($sql);
foreach ($content[$type] as $index => $row) {
$bindValues = [];
foreach ($columns as $column) {
if (!array_key_exists($column, $row) || $row[$column] === null) {
$bindValues[] = null;
} else {
$bindValues[] = $row[$column];
}
}
$stmt->bind_param($typesString, ...$bindValues);
$stmt->execute();
$successCount++;
}
$stmt->close();
}
$rangNote = intval($content['rang_konfiguration']['rang_note_id'] ?? 0);
$orderBestRang = $content['rang_konfiguration']['order_best_rang'] ?? '';
$allowableOrderValues = ['ASC', 'DESC'];
if ($rangNote > 0) {
$mysqli->query("INSERT INTO $tableVar (`name`, `value`) VALUES ('rangNote', '" . $rangNote . "') ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)");
}
if (in_array($orderBestRang, $allowableOrderValues, true)) {
$mysqli->query("INSERT INTO $tableVar (`name`, `value`) VALUES ('orderBestRang', '" . $orderBestRang . "') ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)");
}
if (isset($content['bezeichnungen']['singular']) && $content['bezeichnungen']['singular'] !== null) {
$stmt = $mysqli->prepare("INSERT INTO $tableVar (`name`, `value`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)");
$varName = 'personEinzahl';
$stmt->bind_param("ss", $varName, $content['bezeichnungen']['singular']);
$stmt->execute();
$stmt->close();
}
if (isset($content['bezeichnungen']['plural']) && $content['bezeichnungen']['plural'] !== null) {
$stmt = $mysqli->prepare("INSERT INTO $tableVar (`name`, `value`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)");
$varName = 'personMehrzahl';
$stmt->bind_param("ss", $varName, $content['bezeichnungen']['plural']);
$stmt->execute();
$stmt->close();
}
$noten = db_select($mysqli, $tableNotenBezeichnungen, "id, berechnung, type");
$notenById = array_column($noten, null, 'id');
$berechnungen = [];
foreach ($notenById as $id => $sn) {
if ($sn['type'] === 'berechnung') {
$berechnungen[] = $sn;
}
}
if (empty($berechnungen)) {
$mysqli->commit();
echo json_encode(['success' => true, 'message' => "Successfully imported $successCount rows."]);
exit;
}
$notenRechner = new NotenRechner();
$dependencyMap = [];
foreach ($berechnungen as $calc) {
$neededIdsArrayWithRun = $notenRechner->getBenoetigteIdsComplexWithRun($calc['berechnung']);
if (empty($neededIdsArrayWithRun) || count($neededIdsArrayWithRun) < 2) {
continue;
}
$calcId = (int)$calc['id'];
$neededIdsArray = $neededIdsArrayWithRun;
unset($neededIdsArray['targetRun']);
unset($neededIdsArray['targetGeraet']);
$targetRunId = $neededIdsArrayWithRun['targetRun'];
foreach ($neededIdsArray as $key => $needed) {
$nId = (int)$needed['noteId'];
$gId = is_numeric($needed['geraetId']) ? (int)$needed['geraetId'] : $needed['geraetId'];
$nodeKey = $calcId . '|' . $gId . '|' . $targetRunId;
if (!isset($dependencyMap[$nId])) {
$dependencyMap[$nId] = [];
}
$dependencyMap[$nId][$nodeKey] = [$calcId, $gId, [$targetRunId]];
}
}
function getCompleteDependencyChain($id, $directMap, $visited = [])
{
if (!isset($directMap[$id])) {
return [];
}
$allDependencies = [];
foreach ($directMap[$id] as $nodeKey => $complexNode) {
if (isset($visited[$nodeKey])) {
continue;
}
$visited[$nodeKey] = true;
$allDependencies[$nodeKey] = $complexNode;
$childDependencies = getCompleteDependencyChain($complexNode[0], $directMap, $visited);
foreach ($childDependencies as $childKey => $childNode) {
$allDependencies[$childKey] = $childNode;
$visited[$childKey] = true;
}
}
return $allDependencies;
}
$flatDependencyMap = [];
foreach (array_keys($notenById) as $id) {
$chain = getCompleteDependencyChain($id, $dependencyMap);
if (!empty($chain)) {
$flatDependencyMap[$id] = array_values($chain);
}
}
$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);
$stmt->bind_param("si", $jsonString, $id);
$stmt->execute();
}
$stmt->close();
$mysqli->commit();
echo json_encode(['success' => true, 'message' => "Successfully imported $successCount rows."]);
require_once $baseDir . '/../scripts/cache/cache-creators/regenerate-display-dependencies-cache.php';
require_once $baseDir . '/../scripts/cache/cache-creators/regenerate-noten-cache.php';
generateIntersectCache($mysqli, $baseDir);
regenerate_noten_cache($mysqli, $tableNotenBezeichnungen, $baseDir);
} catch (mysqli_sql_exception $e) {
$mysqli->rollback();
unlink($destination);
if ($e->getCode() === 1048) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => "Import failed: A required data field is missing in your preset file."]);
exit;
} else {
http_response_code(400);
echo json_encode(['success' => false, 'message' => "Database error during import." . " Error Code: " . $e->getMessage()]);
exit;
}
} finally {
$mysqli->close();
$allFiles = glob($uploadDir . '*.json');
$timestamps = array_map(function($file) {
$jsonContent = file_get_contents($file) ?? '';
$data = json_decode($jsonContent, true) ?? [];
return $data['added_timestamp'] ?? 0;
}, $allFiles);
array_multisort($timestamps, SORT_DESC, $allFiles);
$filesToDelete = array_slice($allFiles, 3);
foreach ($filesToDelete as $file) {
unlink($file);
}
}