load(); } $common = $mysydeDir . "/common/common_functions.inc.php"; require_once($common); $connEnv = (local_environment()) ? $mysydeDir . "/dc.config.php" : $mysydeDir . "/dc-server.config.php"; require_once($connEnv); db_connect(); // Prüft ob der aktuelle User Wiki-Schreibrechte hat (r-wiki oder r-wiki-br) function ajax_has_wiki_edit(): bool { $mid = $GLOBALS['main_contact']['master_mandant_id'] ?? 0; $uid = $GLOBALS['main_contact']['id'] ?? 0; return get_permission_state('r-wiki', $mid, $uid) == 1 || get_permission_state('r-wiki-br', $mid, $uid) == 1; } // Betriebsrat darf einen Post nur bearbeiten, wenn er in einer freigegebenen Kategorie liegt. // Gibt false zurück wenn Bearbeitung verboten, true wenn erlaubt. function ajax_can_edit_post(int $postId): bool { $mid = $GLOBALS['main_contact']['master_mandant_id'] ?? 0; $uid = $GLOBALS['main_contact']['id'] ?? 0; if (get_permission_state('r-wiki', $mid, $uid) == 1) { return true; // Redakteur darf immer } if (get_permission_state('r-wiki-br', $mid, $uid) != 1) { return false; // Kein Wiki-Recht } // Betriebsrat: Post muss in betriebsrat_editable Kategorie liegen $res = mysqli_query($GLOBALS['mysql_con'], "SELECT COUNT(*) AS cnt FROM knowledgecenter_category_post kcp JOIN knowledgecenter_categories_update kcu ON kcu.id = kcp.category_id WHERE kcp.post_id = $postId AND kcu.betriebsrat_editable = 1"); $row = mysqli_fetch_assoc($res); return $row && (int)$row['cnt'] > 0; } // AJAX-Handler: Falls per POST eine Aktion übergeben wurde, diese verarbeiten und das Skript beenden. if (isset($_POST["action"])) { header('Content-Type: application/json'); switch ($_POST["action"]) { case 'update_categories_sorting': update_categories_sorting(); break; case 'update_category_detail': update_category_detail(); break; case 'update_subcategory_sorting': update_subcategory_sorting(); break; case 'link_subcategory': link_subcategory(); break; case 'unlink_subcategory': unlink_subcategory(); break; case 'update_category_links': update_category_links(); break; case 'delete_category': delete_category(); break; case 'update_post_version': update_post_version(); break; case 'insert_post_version': insert_post_version(); break; case 'create_post_draft': create_post_draft(); break; case 'ensure_post_gallery_folder': ensure_post_gallery_folder(); break; case 'delete_post_version': delete_post_version(); break; case 'get_post_comments': get_post_comments(); break; case 'insert_comment': insert_comment(); break; case 'delete_comment': delete_comment(); break; case 'update_post_categories': update_post_categories(); break; case 'get_post_list': get_post_list(); break; case 'get_post_files': get_post_files(); break; case 'update_post_contacts': update_post_contacts(); break; case 'get_contact_cards': get_contact_cards(); break; case 'search_posts': search_posts(); break; case 'update_post_pdf_inline': update_post_pdf_inline(); break; case 'update_post_colors': update_post_colors(); break; case 'delete_post': delete_post(); break; case 'update_post_mandants': // Erwarte post_id und einen JSON-codierten Array für mandant IDs $postId = (int) ($_POST['post_id'] ?? 0); $mandantIds = json_decode($_POST['mandants'], true) ?: []; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $result = update_post_mandants($postId, $mandantIds); echo json_encode(is_bool($result) && $result ? ['success' => true] : ['error' => $result]); exit; case 'update_post_departments': $postId = (int) ($_POST['post_id'] ?? 0); $departmentIds = json_decode($_POST['departments'], true) ?: []; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $result = update_post_departments($postId, $departmentIds); echo json_encode(is_bool($result) && $result ? ['success' => true] : ['error' => $result]); exit; case 'update_post_roles': $postId = (int) ($_POST['post_id'] ?? 0); $roleIds = json_decode($_POST['roles'], true) ?: []; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $result = update_post_roles($postId, $roleIds); echo json_encode(is_bool($result) && $result ? ['success' => true] : ['error' => $result]); exit; case 'update_post_einrichts': $postId = (int) ($_POST['post_id'] ?? 0); $einrichtIds = json_decode($_POST['einrichts'], true) ?: []; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $result = update_post_einrichts($postId, $einrichtIds); echo json_encode(is_bool($result) && $result ? ['success' => true] : ['error' => $result]); exit; case 'update_post_fachbereiche': $postId = (int) ($_POST['post_id'] ?? 0); $fachbereichIds = json_decode($_POST['fachbereiche'], true) ?: []; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $result = update_post_fachbereiche($postId, $fachbereichIds); echo json_encode(is_bool($result) && $result ? ['success' => true] : ['error' => $result]); exit; case 'update_post_products': $postId = (int) ($_POST['post_id'] ?? 0); $productIds = json_decode($_POST['products'] ?? '[]', true) ?: []; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $result = update_post_products($postId, $productIds); echo json_encode(is_bool($result) && $result ? ['success' => true] : ['error' => $result]); exit; case 'save_post_files': save_post_files(); break; case 'delete_post_file': delete_post_file(); break; case 'update_post_certificate': update_post_certificate(); break; case 'update_post_form': $postId = (int) ($_POST['post_id'] ?? 0); $formId = (int) ($_POST['form_id'] ?? 0); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $result = update_post_form($postId, $formId); echo json_encode($result === true ? ['success' => true] : ['error' => $result]); exit; default: echo json_encode(['error' => 'Ungültige Aktion']); exit; } exit; } /** * Aktualisiert die Sortierung der Kategorien in der Hauptliste. */ function update_categories_sorting() { if (!isset($_POST['order']) || !is_array($_POST['order'])) { echo json_encode(['error' => 'Keine Sortierdaten übergeben']); exit; } $order = $_POST['order']; foreach ($order as $index => $categoryId) { $sorting = $index + 1; // 1-indexiert $categoryId = (int) $categoryId; $query = "UPDATE knowledgecenter_categories_update SET sorting = $sorting WHERE id = $categoryId"; if (!mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['error' => "Datenbankfehler bei Kategorie-ID $categoryId"]); exit; } } echo json_encode(['success' => true]); exit; } function update_post_form($postId, $formId) { $checkQuery = "SELECT id FROM knowledgecenter_post_form WHERE post_id = $postId"; $result = mysqli_query($GLOBALS['mysql_con'], $checkQuery); if ($result && mysqli_num_rows($result) > 0) { $query = "UPDATE knowledgecenter_post_form SET form_id = $formId WHERE post_id = $postId"; } else { $query = "INSERT INTO knowledgecenter_post_form (post_id, form_id) VALUES ($postId, $formId)"; } if (mysqli_query($GLOBALS['mysql_con'], $query)) { return true; } else { return 'Fehler beim Speichern der Formular-Zuordnung: ' . mysqli_error($GLOBALS['mysql_con']); } } /** * Speichert oder aktualisiert die sprachspezifischen Inhalte (Translation) einer Kategorie. */ function update_category_detail() { $is_navigation_item = isset($_POST['is_navigation_item']) ? (int) $_POST['is_navigation_item'] : 0; $enable_post_color_pickers = isset($_POST['enable_post_color_pickers']) ? (int) $_POST['enable_post_color_pickers'] : 0; $betriebsrat_editable = isset($_POST['betriebsrat_editable']) ? (int) $_POST['betriebsrat_editable'] : 0; $color_hex = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['color_hex'] ?? ''); $categoryId = (int) ($_POST['id'] ?? 0); $languageId = (int) ($_POST['language_id'] ?? 0); $modified_by = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['modified_by'] ?? ''); $state = isset($_POST['state']) ? (int) $_POST['state'] : 0; if ($languageId <= 0) { echo json_encode(['error' => 'Ungültige Parameter']); exit; } $title = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['title'] ?? ''); $image = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['image'] ?? ''); if ($categoryId === 0) { $insertMain = "INSERT INTO knowledgecenter_categories_update (modified_by, created_at, state, color_hex, enable_post_color_pickers) VALUES ('$modified_by', NOW(), $state, '$color_hex', $enable_post_color_pickers)"; if (!mysqli_query($GLOBALS['mysql_con'], $insertMain)) { echo json_encode(['error' => 'Fehler beim Erstellen der Hauptkategorie: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $categoryId = mysqli_insert_id($GLOBALS['mysql_con']); } $checkQuery = "SELECT id FROM knowledgecenter_category_translations WHERE category_id = $categoryId AND language_id = $languageId LIMIT 1"; $checkResult = mysqli_query($GLOBALS['mysql_con'], $checkQuery); if ($checkResult && mysqli_num_rows($checkResult) > 0) { $query = "UPDATE knowledgecenter_category_translations SET title = '$title', image = '$image', modified_at = NOW(), is_navigation_item = $is_navigation_item WHERE category_id = $categoryId AND language_id = $languageId"; } else { $query = "INSERT INTO knowledgecenter_category_translations (category_id, language_id, title, image, created_at, is_navigation_item) VALUES ($categoryId, $languageId, '$title', '$image', NOW(), $is_navigation_item)"; } if (!mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['error' => 'Datenbankfehler: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $mainUpdate = "UPDATE knowledgecenter_categories_update SET modified_by = '$modified_by', modified_at = NOW(), state = $state, enable_post_color_pickers = $enable_post_color_pickers, betriebsrat_editable = $betriebsrat_editable, color_hex = '$color_hex' WHERE id = $categoryId"; if (!mysqli_query($GLOBALS['mysql_con'], $mainUpdate)) { echo json_encode(['error' => 'Datenbankfehler beim Update der Hauptkategorie: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $forwardUrl = "/intranet/de/wiki/?detail=$categoryId"; if ($is_navigation_item === 1) { $existsNavQuery = "SELECT id FROM main_navigation WHERE forward_url = '$forwardUrl' LIMIT 1"; $navResult = mysqli_query($GLOBALS['mysql_con'], $existsNavQuery); if (mysqli_num_rows($navResult) === 0) { $menuName = mysqli_real_escape_string($GLOBALS['mysql_con'], $title); $queryNav = "INSERT INTO main_navigation ( main_site_id, main_language_id, parent_id, sorting, level, code, menu_name, title_name, active, validity_from, validity_to, modified_date, modified_admin_user_id, forward_type, forward_navigation_id, forward_page_id, forward_url, navigation_icon, hidden, is_landing_page, description ) VALUES ( 1, $languageId, NULL, 9999, 1, 'kc_$categoryId', '$menuName', '$menuName', 1, NULL, NULL, NOW(), 0, 5, 0, 0, '$forwardUrl', 'knowledgecenter', 0, 0, '' )"; mysqli_query($GLOBALS['mysql_con'], $queryNav); } } else { $deleteNavQuery = "DELETE FROM main_navigation WHERE forward_url = '$forwardUrl'"; mysqli_query($GLOBALS['mysql_con'], $deleteNavQuery); } $queryTimestamp = "SELECT modified_at, modified_by FROM knowledgecenter_categories_update WHERE id = $categoryId"; $resultTimestamp = mysqli_query($GLOBALS['mysql_con'], $queryTimestamp); $row = mysqli_fetch_assoc($resultTimestamp); $fmt = new IntlDateFormatter('de_DE', IntlDateFormatter::LONG, IntlDateFormatter::SHORT); $timestamp = strtotime($row['modified_at']); $formattedAt = $fmt->format($timestamp); echo json_encode([ 'success' => true, 'modified_at' => $formattedAt, 'modified_by' => $row['modified_by'], 'category_id' => $categoryId, 'is_navigation_item' => $is_navigation_item ]); exit; } /** * Aktualisiert die Sortierung der verknüpften Unterkategorien. */ function update_subcategory_sorting() { $parentId = (int) ($_POST['parent_id'] ?? 0); $order = $_POST['order'] ?? []; if ($parentId <= 0 || !is_array($order)) { echo json_encode(['error' => 'Ungültige Parameter']); exit; } foreach ($order as $index => $childId) { $childId = (int) $childId; $sorting = $index + 1; $query = "UPDATE knowledgecenter_category_links SET sorting = $sorting WHERE parent_category_id = $parentId AND child_category_id = $childId"; if (!mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['error' => "Fehler beim Sortieren: " . mysqli_error($GLOBALS['mysql_con'])]); exit; } } echo json_encode(['success' => true]); exit; } /** * Verknüpft eine neue Unterkategorie mit der aktuellen Kategorie. */ function link_subcategory() { $parent_id = (int) ($_POST['parent_id'] ?? 0); $child_id = (int) ($_POST['child_id'] ?? 0); if ($parent_id <= 0 || $child_id <= 0) { echo json_encode(['error' => 'Ungültige Parameter']); exit; } // Bestimme den nächsten Sortierwert für die neue Verknüpfung $query = "SELECT IFNULL(MAX(sorting), 0) + 1 AS next_sort FROM knowledgecenter_category_links WHERE parent_category_id = $parent_id"; $result = mysqli_query($GLOBALS['mysql_con'], $query); $row = mysqli_fetch_assoc($result); $nextSort = (int) $row['next_sort']; $insertQuery = "INSERT INTO knowledgecenter_category_links (parent_category_id, child_category_id, sorting) VALUES ($parent_id, $child_id, $nextSort)"; if (mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { echo json_encode(['success' => true]); } else { echo json_encode(['error' => 'Datenbankfehler: ' . mysqli_error($GLOBALS['mysql_con'])]); } exit; } /** * Entfernt die Verknüpfung einer Unterkategorie von der aktuellen Kategorie. */ function unlink_subcategory() { $parent_id = (int) ($_POST['parent_id'] ?? 0); $child_id = (int) ($_POST['child_id'] ?? 0); if ($parent_id <= 0 || $child_id <= 0) { echo json_encode(['error' => 'Ungültige Parameter']); exit; } $query = "DELETE FROM knowledgecenter_category_links WHERE parent_category_id = $parent_id AND child_category_id = $child_id"; if (mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['success' => true]); } else { echo json_encode(['error' => 'Datenbankfehler: ' . mysqli_error($GLOBALS['mysql_con'])]); } exit; } /** * Löscht alte Mandanten-Verknüpfungen und fügt neue ein. */ function update_category_mandants($categoryId, $mandantIds) { // Alte Verknüpfungen löschen $deleteQuery = "DELETE FROM knowledgecenter_category_mandant WHERE category_id = $categoryId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Mandanten-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } // Neue Verknüpfungen einfügen foreach ($mandantIds as $mandantId) { $mandantId = (int) $mandantId; $insertQuery = "INSERT INTO knowledgecenter_category_mandant (category_id, mandant_id, created_at) VALUES ($categoryId, $mandantId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Mandant-ID $mandantId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Department-Verknüpfungen und fügt neue ein. */ function update_category_departments($categoryId, $departmentIds) { $deleteQuery = "DELETE FROM knowledgecenter_category_department WHERE category_id = $categoryId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Department-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } foreach ($departmentIds as $departmentId) { $departmentId = (int) $departmentId; $insertQuery = "INSERT INTO knowledgecenter_category_department (category_id, department_id, created_at) VALUES ($categoryId, $departmentId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Department-ID $departmentId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Rollen-Verknüpfungen und fügt neue ein. */ function update_category_roles($categoryId, $roleIds) { $deleteQuery = "DELETE FROM knowledgecenter_category_role WHERE category_id = $categoryId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Rollen-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } foreach ($roleIds as $roleId) { $roleId = (int) $roleId; $insertQuery = "INSERT INTO knowledgecenter_category_role (category_id, role_id, created_at) VALUES ($categoryId, $roleId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Rollen-ID $roleId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Einrichtungs-Verknüpfungen und fügt neue ein. */ function update_category_einrichts($categoryId, $einrichtIds) { $deleteQuery = "DELETE FROM knowledgecenter_category_einricht WHERE category_id = $categoryId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Einrichtungs-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } foreach ($einrichtIds as $einrichtId) { $einrichtId = (int) $einrichtId; $insertQuery = "INSERT INTO knowledgecenter_category_einricht (category_id, einricht_id, created_at) VALUES ($categoryId, $einrichtId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Einrichtungs-ID $einrichtId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Fachbereich-Verknüpfungen und fügt neue ein. */ function update_category_fachbereiche($categoryId, $fachbereichIds) { $deleteQuery = "DELETE FROM knowledgecenter_category_fachbereich WHERE category_id = $categoryId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Fachbereich-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } foreach ($fachbereichIds as $fachbereichId) { $fachbereichId = (int) $fachbereichId; $insertQuery = "INSERT INTO knowledgecenter_category_fachbereich (category_id, fachbereich_id, created_at) VALUES ($categoryId, $fachbereichId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Fachbereich-ID $fachbereichId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Kombinierte Funktion, die alle fünf Link-Tabellen aktualisiert. */ function update_category_links() { $categoryId = (int) ($_POST['id'] ?? 0); $mandantIds = json_decode($_POST['mandants'], true) ?: []; $departmentIds = json_decode($_POST['departments'], true) ?: []; $roleIds = json_decode($_POST['roles'], true) ?: []; $einrichtIds = json_decode($_POST['einrichts'] ?? '[]', true) ?: []; $fachbereichIds = json_decode($_POST['fachbereiche'] ?? '[]', true) ?: []; $errors = []; $result = update_category_mandants($categoryId, $mandantIds); if ($result !== true) { $errors[] = $result; } $result = update_category_departments($categoryId, $departmentIds); if ($result !== true) { $errors[] = $result; } $result = update_category_roles($categoryId, $roleIds); if ($result !== true) { $errors[] = $result; } $result = update_category_einrichts($categoryId, $einrichtIds); if ($result !== true) { $errors[] = $result; } $result = update_category_fachbereiche($categoryId, $fachbereichIds); if ($result !== true) { $errors[] = $result; } if (empty($errors)) { $savedMandants = []; foreach ($mandantIds as $id) { $id = (int) $id; $sql = "SELECT id, description FROM main_mandant WHERE id = $id LIMIT 1"; $res = mysqli_query($GLOBALS['mysql_con'], $sql); if ($res && mysqli_num_rows($res) > 0) { $row = mysqli_fetch_assoc($res); $savedMandants[] = ['value' => $row['id'], 'name' => $row['description']]; } } $savedDepartments = []; foreach ($departmentIds as $id) { $id = (int) $id; $sql = "SELECT id, description FROM main_department WHERE id = $id LIMIT 1"; $res = mysqli_query($GLOBALS['mysql_con'], $sql); if ($res && mysqli_num_rows($res) > 0) { $row = mysqli_fetch_assoc($res); $savedDepartments[] = ['value' => $row['id'], 'name' => $row['description']]; } } $savedRoles = []; foreach ($roleIds as $id) { $id = (int) $id; $sql = "SELECT id, description FROM main_role WHERE id = $id LIMIT 1"; $res = mysqli_query($GLOBALS['mysql_con'], $sql); if ($res && mysqli_num_rows($res) > 0) { $row = mysqli_fetch_assoc($res); $savedRoles[] = ['value' => $row['id'], 'name' => $row['description']]; } } $savedEinrichts = []; foreach ($einrichtIds as $id) { $id = (int) $id; $sql = "SELECT id, description FROM organigramm_einricht WHERE id = $id LIMIT 1"; $res = mysqli_query($GLOBALS['mysql_con'], $sql); if ($res && mysqli_num_rows($res) > 0) { $row = mysqli_fetch_assoc($res); $savedEinrichts[] = ['value' => $row['id'], 'name' => $row['description']]; } } $savedFachbereiche = []; foreach ($fachbereichIds as $id) { $id = (int) $id; $sql = "SELECT id, description FROM organogramm_space WHERE id = $id LIMIT 1"; $res = mysqli_query($GLOBALS['mysql_con'], $sql); if ($res && mysqli_num_rows($res) > 0) { $row = mysqli_fetch_assoc($res); $savedFachbereiche[] = ['value' => $row['id'], 'name' => $row['description']]; } } echo json_encode([ 'success' => true, 'mandants' => $savedMandants, 'departments' => $savedDepartments, 'roles' => $savedRoles, 'einrichts' => $savedEinrichts, 'fachbereiche' => $savedFachbereiche, ]); } else { echo json_encode(['error' => implode("; ", $errors)]); } exit; } function delete_category() { $categoryId = (int) ($_POST['id'] ?? 0); if ($categoryId <= 0) { echo json_encode(['error' => 'Ungültige Kategorie-ID']); exit; } // Lösche Navigationseintrag für diese Kategorie, falls vorhanden $forwardUrl = "/intranet/de/wiki/?detail=" . $categoryId; $navCheckQuery = "SELECT id FROM main_navigation WHERE forward_url = '$forwardUrl' LIMIT 1"; $navCheckResult = mysqli_query($GLOBALS['mysql_con'], $navCheckQuery); if ($navCheckResult && mysqli_num_rows($navCheckResult) > 0) { mysqli_query($GLOBALS['mysql_con'], "DELETE FROM main_navigation WHERE forward_url = '$forwardUrl'"); } // Bei korrekter Fremdschlüsseldefinition (z. B. ON DELETE CASCADE) reicht oft ein DELETE aus. $query = "DELETE FROM knowledgecenter_categories_update WHERE id = $categoryId"; if (mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['success' => true]); } else { echo json_encode(['error' => 'Fehler beim Löschen: ' . mysqli_error($GLOBALS['mysql_con'])]); } exit; } function normalize_hex_color($color, $default = '#FFFFFF') { $color = trim((string) $color); if (preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/', $color)) { return strtoupper($color); } return $default; } /** * Aktualisiert eine bestehende Post-Version. */ function update_post_version() { // Stelle sicher, dass alle Sprachdaten als Array übermittelt wurden if (!isset($_POST['title']) || !is_array($_POST['title'])) { echo json_encode(['error' => 'Keine Sprachdaten übermittelt']); exit; } // Hole die Beitrags-ID aus den POST-Daten (wichtig für den Insert-Fallback) $postId = (int) ($_POST['post_id'] ?? 0); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } $keepModifiedAt = isset($_POST['keep_modified_at']) && (int) $_POST['keep_modified_at'] === 1; $backgroundColor = normalize_hex_color($_POST['background_color'] ?? '#FFFFFF', '#FFFFFF'); $textColor = normalize_hex_color($_POST['text_color'] ?? '#000000', '#000000'); $updatePostQuery = "UPDATE knowledgecenter_posts SET background_color = '$backgroundColor', text_color = '$textColor'" . ($keepModifiedAt ? "" : ", modified_at = NOW()") . " WHERE id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $updatePostQuery)) { echo json_encode(['error' => 'Fehler beim Aktualisieren der Post-Farben: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } // Iteriere über alle übermittelten Sprachfelder foreach ($_POST['title'] as $langId => $title) { $langId = (int) $langId; $title = mysqli_real_escape_string($GLOBALS['mysql_con'], $title); $image = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['image'][$langId] ?? ''); $teaser = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['teaser'][$langId] ?? ''); $content = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['content'][$langId] ?? ''); $summary = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['summary'][$langId] ?? ''); $author_id = isset($_POST['author_id'][$langId]) ? (int) $_POST['author_id'][$langId] : 0; $link = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['link'][$langId] ?? ''); $link_label = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['link_label'][$langId] ?? ''); // State-Rohwert (Default 0 = Inaktiv, falls nichts übergeben) $stateRaw = $_POST['state'][$langId] ?? '0'; // In Integer casten $state = (int) $stateRaw; // Hier die neuen Felder: $valid_from = isset($_POST['valid_from'][$langId]) ? mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['valid_from'][$langId]) : 'NULL'; $valid_until = isset($_POST['valid_until'][$langId]) ? mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['valid_until'][$langId]) : 'NULL'; // Wenn ein Datum übergeben wird, müssen wir es als Zeichenkette in SQL einbinden, andernfalls NULL $valid_from_sql = ($valid_from !== 'NULL' && !empty($valid_from)) ? "'$valid_from'" : "NULL"; $valid_until_sql = ($valid_until !== 'NULL' && !empty($valid_until)) ? "'$valid_until'" : "NULL"; // Prüfe, ob es bereits eine Version gibt… $versionId = isset($_POST['version_id'][$langId]) ? (int) $_POST['version_id'][$langId] : 0; if ($versionId <= 0) { // INSERT: Ermittle die neue Versionnummer… $query = "SELECT MAX(version_number) AS max_ver FROM knowledgecenter_post_versions WHERE post_id = $postId AND language_id = $langId"; $result = mysqli_query($GLOBALS['mysql_con'], $query); $row = mysqli_fetch_assoc($result); $newVersion = ((int) $row['max_ver']) + 1; $insertModifiedAtSql = "NOW()"; if ($keepModifiedAt) { $prevQuery = "SELECT modified_at FROM knowledgecenter_post_versions WHERE post_id = $postId AND language_id = $langId ORDER BY version_number DESC LIMIT 1"; $prevResult = mysqli_query($GLOBALS['mysql_con'], $prevQuery); if ($prevResult && mysqli_num_rows($prevResult) > 0) { $prevRow = mysqli_fetch_assoc($prevResult); if (!empty($prevRow['modified_at'])) { $prevModifiedAt = mysqli_real_escape_string($GLOBALS['mysql_con'], $prevRow['modified_at']); $insertModifiedAtSql = "'$prevModifiedAt'"; } } } $insertQuery = " INSERT INTO knowledgecenter_post_versions (post_id, language_id, version_number, title, image, link, link_label, teaser, content, summary, author_id, state, modified_at, valid_from, valid_until, background_color, text_color) VALUES ($postId, $langId, $newVersion, '$title', '$image', '$link', '$link_label', '$teaser', '$content', '$summary', $author_id, $state, $insertModifiedAtSql, $valid_from_sql, $valid_until_sql, '$backgroundColor', '$textColor') "; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { echo json_encode(['error' => 'Fehler beim Einfügen für Sprache ' . $langId . ': ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } continue; } // UPDATE: Aktualisiere auch die Datumsfelder $query = " UPDATE knowledgecenter_post_versions SET title = '$title', image = '$image', link = '$link', link_label = '$link_label', teaser = '$teaser', content = '$content', summary = '$summary', author_id = $author_id, state = $state, valid_from = $valid_from_sql, valid_until = $valid_until_sql, background_color = '$backgroundColor', text_color = '$textColor'" . ($keepModifiedAt ? "" : ",\n modified_at = NOW()") . " WHERE id = $versionId AND language_id = $langId "; if (!mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['error' => 'Fehler beim Aktualisieren für Sprache ' . $langId . ': ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } } echo json_encode(['success' => true]); exit; } /** * Erstellt eine neue Post-Version basierend auf den übermittelten Feldern. */ function insert_post_version() { // Hole die Beitrags-ID aus den POST-Daten (0 = neuer Beitrag) $postId = (int) ($_POST['post_id'] ?? 0); // Initiale Kategorie (falls über Form übergeben) $initialCategoryId = isset($_POST['initial_category_id']) ? (int) $_POST['initial_category_id'] : 0; $initialProductId = isset($_POST['InitialProduct']) ? (int) $_POST['InitialProduct'] : 0; $keepModifiedAt = isset($_POST['keep_modified_at']) && (int) $_POST['keep_modified_at'] === 1; $backgroundColor = normalize_hex_color($_POST['background_color'] ?? '#FFFFFF', '#FFFFFF'); $textColor = normalize_hex_color($_POST['text_color'] ?? '#000000', '#000000'); // Wenn keine gültige Post-ID vorliegt, erstelle einen neuen Beitrag if ($postId <= 0) { $insertPostQuery = "INSERT INTO knowledgecenter_posts (created_at, background_color, text_color) VALUES (NOW(), '$backgroundColor', '$textColor')"; if (!mysqli_query($GLOBALS['mysql_con'], $insertPostQuery)) { echo json_encode(['error' => 'Fehler beim Erstellen des neuen Beitrags: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } // Verwende die neu generierte Post-ID für den weiteren Insert $postId = mysqli_insert_id($GLOBALS['mysql_con']); } else { $updatePostQuery = "UPDATE knowledgecenter_posts SET background_color = '$backgroundColor', text_color = '$textColor'" . ($keepModifiedAt ? "" : ",\n modified_at = NOW()") . " WHERE id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $updatePostQuery)) { echo json_encode(['error' => 'Fehler beim Aktualisieren der Post-Farben: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } } // Kategorie-Verknüpfung bei neu angelegtem Beitrag if ($initialCategoryId > 0 && $postId > 0) { $catInsert = "INSERT INTO knowledgecenter_category_post (post_id, category_id) VALUES ($postId, $initialCategoryId)"; mysqli_query($GLOBALS['mysql_con'], $catInsert); } if ($initialProductId > 0 && $postId > 0) { $prodInsert = "INSERT INTO product_knowledgecenter_post_link (product_id, post_id) VALUES ($initialProductId, $postId)"; mysqli_query($GLOBALS['mysql_con'], $prodInsert); } $folderInfo = ensure_post_gallery_dir($postId); if (!$folderInfo['success']) { echo json_encode(['error' => 'Fehler beim Erstellen des Beitragsordners: ' . $folderInfo['error']]); exit; } // Sicherstellen, dass Sprachdaten übermittelt wurden if (!isset($_POST['title']) || !is_array($_POST['title'])) { echo json_encode(['error' => 'Keine Sprachdaten übermittelt']); exit; } $newIds = []; foreach ($_POST['title'] as $langId => $title) { $langId = (int) $langId; $title = trim($title); $title = mysqli_real_escape_string($GLOBALS['mysql_con'], $title); $image = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['image'][$langId] ?? ''); $teaser = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['teaser'][$langId] ?? ''); $content = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['content'][$langId] ?? ''); $summary = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['summary'][$langId] ?? ''); $link = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['link'][$langId] ?? ''); $link_label = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['link_label'][$langId] ?? ''); $author_id = isset($_POST['author_id'][$langId]) ? (int) $_POST['author_id'][$langId] : 0; // State-Rohwert (Default 0 = Inaktiv, falls nichts übergeben) $stateRaw = $_POST['state'][$langId] ?? '0'; // In Integer casten $state = (int) $stateRaw; $valid_from = isset($_POST['valid_from'][$langId]) ? mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['valid_from'][$langId]) : 'NULL'; $valid_until = isset($_POST['valid_until'][$langId]) ? mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['valid_until'][$langId]) : 'NULL'; $valid_from_sql = ($valid_from !== 'NULL' && !empty($valid_from)) ? "'$valid_from'" : "NULL"; $valid_until_sql = ($valid_until !== 'NULL' && !empty($valid_until)) ? "'$valid_until'" : "NULL"; $query = "SELECT MAX(version_number) AS max_ver FROM knowledgecenter_post_versions WHERE post_id = $postId AND language_id = $langId"; $result = mysqli_query($GLOBALS['mysql_con'], $query); $row = mysqli_fetch_assoc($result); $newVersion = ((int) $row['max_ver']) + 1; $insertModifiedAtSql = "NOW()"; if ($keepModifiedAt) { $prevQuery = "SELECT modified_at FROM knowledgecenter_post_versions WHERE post_id = $postId AND language_id = $langId ORDER BY version_number DESC LIMIT 1"; $prevResult = mysqli_query($GLOBALS['mysql_con'], $prevQuery); if ($prevResult && mysqli_num_rows($prevResult) > 0) { $prevRow = mysqli_fetch_assoc($prevResult); if (!empty($prevRow['modified_at'])) { $prevModifiedAt = mysqli_real_escape_string($GLOBALS['mysql_con'], $prevRow['modified_at']); $insertModifiedAtSql = "'$prevModifiedAt'"; } } } $insertQuery = "INSERT INTO knowledgecenter_post_versions (post_id, language_id, version_number, title, image, link, link_label, teaser, content, summary, author_id, state, modified_at, valid_from, valid_until, background_color, text_color) VALUES ($postId, $langId, $newVersion, '$title', '$image', '$link', '$link_label', '$teaser', '$content', '$summary', $author_id, $state, $insertModifiedAtSql, $valid_from_sql, $valid_until_sql, '$backgroundColor', '$textColor')"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { echo json_encode(['error' => "Fehler beim Einfügen für Sprache $langId: " . mysqli_error($GLOBALS['mysql_con'])]); exit; } $newIds[$langId] = mysqli_insert_id($GLOBALS['mysql_con']); } echo json_encode([ 'success' => true, 'new_post_id' => $postId, 'gallery_start_path' => $folderInfo['start_path'], 'new_ids' => $newIds ]); exit; } function get_post_folder_hash($postId) { return substr(sha1('kc_post_' . (int) $postId), 0, 24); } function ensure_post_gallery_dir($postId) { $postId = (int) $postId; if ($postId <= 0) { return ['success' => false, 'error' => 'Ungültige Post-ID']; } $hash = get_post_folder_hash($postId); $galleryRelativePath = 'knowledgecenter_update/posts/' . $hash; $basePath = $_SERVER['DOCUMENT_ROOT'] . '/userdata/knowledgecenter_update/posts'; $postPath = $basePath . '/' . $hash; if (!is_dir($basePath) && !@mkdir($basePath, 0775, true)) { return ['success' => false, 'error' => 'Basisordner konnte nicht erstellt werden']; } if (!is_dir($postPath) && !@mkdir($postPath, 0775, true)) { return ['success' => false, 'error' => 'Post-Ordner konnte nicht erstellt werden']; } // Globalen shared-Symlink idempotent anlegen. Ziel ist relativ, damit der // Symlink bei Backups/Restores oder Mount-Point-Wechseln stabil bleibt. // Fehler hier sind nicht-blockierend: ein fehlender shared-Symlink darf die // Post-Erstellung nicht verhindern. $sharedLink = $postPath . '/shared'; if (!is_link($sharedLink) && !file_exists($sharedLink)) { @symlink('../../shared', $sharedLink); } return [ 'success' => true, 'hash' => $hash, 'start_path' => $galleryRelativePath, ]; } function delete_post_gallery_dir($postId) { $postId = (int) $postId; if ($postId <= 0) { return ['success' => false, 'error' => 'Ungültige Post-ID']; } $userdataRoot = realpath($_SERVER['DOCUMENT_ROOT'] . '/userdata'); if ($userdataRoot === false) { return ['success' => false, 'error' => 'userdata-Verzeichnis nicht gefunden']; } $postsBasePath = $userdataRoot . '/knowledgecenter_update/posts'; $postsBaseReal = realpath($postsBasePath); if ($postsBaseReal === false) { return ['success' => true, 'skipped' => true]; } $targetPath = $postsBaseReal . '/' . get_post_folder_hash($postId); $targetReal = realpath($targetPath); if ($targetReal === false) { return ['success' => true, 'skipped' => true]; } if ($targetReal !== $postsBaseReal && strpos($targetReal, $postsBaseReal . DIRECTORY_SEPARATOR) !== 0) { return ['success' => false, 'error' => 'Ungültiger Zielpfad']; } // Symlinks im Top-Level zuerst entfernen, BEVOR RecursiveDirectoryIterator startet. // unlink() auf einem Symlink löscht nur den Symlink selbst, nicht das Ziel — so // bleiben referenzierte globale Ressourcen (z.B. shared/) garantiert unangetastet. foreach (scandir($targetReal, SCANDIR_SORT_NONE) as $entry) { if ($entry === '.' || $entry === '..') continue; $entryPath = $targetReal . '/' . $entry; if (is_link($entryPath)) { if (!@unlink($entryPath)) { return ['success' => false, 'error' => 'Symlink konnte nicht gelöscht werden: ' . $entry]; } } } $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($targetReal, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST ); foreach ($iterator as $item) { $itemPath = $item->getPathname(); // Defense-in-Depth: falls trotz Top-Level-Bereinigung ein Symlink auftaucht // (z.B. tief verschachtelt), niemals dem Ziel folgen. if (is_link($itemPath)) { if (!@unlink($itemPath)) { return ['success' => false, 'error' => 'Symlink konnte nicht gelöscht werden']; } continue; } if ($item->isDir()) { if (!@rmdir($itemPath)) { return ['success' => false, 'error' => 'Unterordner konnte nicht gelöscht werden']; } } else { if (!@unlink($itemPath)) { return ['success' => false, 'error' => 'Datei konnte nicht gelöscht werden']; } } } if (!@rmdir($targetReal)) { return ['success' => false, 'error' => 'Post-Ordner konnte nicht gelöscht werden']; } return ['success' => true]; } function create_post_draft() { $insertPostQuery = "INSERT INTO knowledgecenter_posts (created_at) VALUES (NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertPostQuery)) { echo json_encode(['error' => 'Fehler beim Erstellen des Entwurfs: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $postId = (int) mysqli_insert_id($GLOBALS['mysql_con']); $folderInfo = ensure_post_gallery_dir($postId); if (!$folderInfo['success']) { echo json_encode(['error' => 'Entwurf erstellt, aber Ordner fehlgeschlagen: ' . $folderInfo['error']]); exit; } echo json_encode([ 'success' => true, 'new_post_id' => $postId, 'post_hash' => $folderInfo['hash'], 'gallery_start_path' => $folderInfo['start_path'], ]); exit; } function ensure_post_gallery_folder() { $postId = (int) ($_POST['post_id'] ?? 0); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $folderInfo = ensure_post_gallery_dir($postId); if (!$folderInfo['success']) { echo json_encode(['error' => 'Fehler beim Erstellen des Beitragsordners: ' . $folderInfo['error']]); exit; } echo json_encode([ 'success' => true, 'post_id' => $postId, 'post_hash' => $folderInfo['hash'], 'gallery_start_path' => $folderInfo['start_path'], ]); exit; } function delete_post_version() { $postId = (int) ($_POST['post_id'] ?? 0); $versionNumber = (int) ($_POST['version_number'] ?? 0); if ($postId <= 0 || $versionNumber <= 0) { echo json_encode(['error' => 'Ungültige Parameter']); exit; } $isEmbedded = (int) ($_POST['embedded'] ?? 0); // Lösche alle Versionseinträge für diesen Beitrag und diese Version (alle Sprachvarianten) $query = "DELETE FROM knowledgecenter_post_versions WHERE post_id = $postId AND version_number = $versionNumber"; if (!mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['error' => 'Fehler beim Löschen der Version: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } // Prüfe, ob noch Versionen zu diesem Beitrag existieren $queryCount = "SELECT COUNT(*) AS cnt FROM knowledgecenter_post_versions WHERE post_id = $postId"; $resCount = mysqli_query($GLOBALS['mysql_con'], $queryCount); if ($resCount && mysqli_num_rows($resCount) > 0) { $row = mysqli_fetch_assoc($resCount); $countVersions = (int) $row['cnt']; } else { $countVersions = 0; } $response = ['success' => true]; // Wenn keine Versionen mehr vorhanden sind: Beitrag löschen und Redirect-Pfad zurückgeben if ($countVersions === 0) { $deletePostQuery = "DELETE FROM knowledgecenter_posts WHERE id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deletePostQuery)) { echo json_encode(['error' => 'Fehler beim Löschen des Beitrags: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $deleteFolderResult = delete_post_gallery_dir($postId); if (!$deleteFolderResult['success']) { echo json_encode(['error' => 'Beitrag gelöscht, aber Ordner konnte nicht gelöscht werden: ' . $deleteFolderResult['error']]); exit; } $action = ($isEmbedded) ? 'PostList' : 'Category'; $response['redirect'] = '?action=' . $action . '&embedded=' . $isEmbedded; } echo json_encode($response); exit; } function get_post_comments() { $postId = (int) ($_POST['post_id'] ?? 0); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } // Achte darauf, dass auch parent_id abgerufen wird. $query = "SELECT kc.*, mc.name AS author FROM knowledgecenter_post_comments AS kc LEFT JOIN main_contact AS mc ON kc.author_id = mc.id WHERE kc.post_id = $postId ORDER BY kc.created_at ASC"; $result = mysqli_query($GLOBALS['mysql_con'], $query); if (!$result) { echo json_encode(['error' => 'Datenbankfehler: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $comments = []; while ($row = mysqli_fetch_assoc($result)) { $comments[] = $row; } echo json_encode(['success' => true, 'comments' => $comments]); exit; } function insert_comment() { $postId = (int) ($_POST['post_id'] ?? 0); $text = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['text'] ?? ''); $author_id = (int) ($_POST['author_id'] ?? 0); // Neuen Parameter für Antwort (optional) $parentId = isset($_POST['parent_id']) ? (int) $_POST['parent_id'] : 0; if ($postId <= 0 || empty($text) || $author_id <= 0) { echo json_encode(['error' => 'Ungültige Eingaben: Post-ID, Text und Author-ID sind erforderlich.']); exit; } // Falls kein Parent vorhanden, setze NULL $parentValue = ($parentId > 0) ? $parentId : "NULL"; $query = "INSERT INTO knowledgecenter_post_comments (post_id, text, author_id, parent_id, created_at) VALUES ($postId, '$text', $author_id, $parentValue, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['error' => 'Datenbankfehler: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $newCommentId = mysqli_insert_id($GLOBALS['mysql_con']); echo json_encode(['success' => true, 'id' => $newCommentId]); exit; } function delete_comment() { // Kommentar-ID aus den POST-Daten $commentId = (int) ($_POST['comment_id'] ?? 0); if ($commentId <= 0) { echo json_encode(['error' => 'Ungültige Kommentar-ID']); exit; } // Kommentar auslesen $query = "SELECT author_id FROM knowledgecenter_post_comments WHERE id = $commentId LIMIT 1"; $result = mysqli_query($GLOBALS['mysql_con'], $query); if (!$result || mysqli_num_rows($result) == 0) { echo json_encode(['error' => 'Kommentar nicht gefunden.']); exit; } $row = mysqli_fetch_assoc($result); $commentAuthorId = (int) $row['author_id']; // Den aktuell angemeldeten Benutzer ermitteln (Sicherstellen, dass $GLOBALS['main_contact']['id'] gesetzt ist) $currentUserId = (int) $_POST['main_contact_id']; // Nur eigene Kommentare löschen if ($commentAuthorId !== $currentUserId) { echo json_encode(['error' => 'Sie dürfen diesen Kommentar nicht löschen.']); exit; } // Kommentar löschen $deleteQuery = "DELETE FROM knowledgecenter_post_comments WHERE id = $commentId"; if (mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { echo json_encode(['success' => true]); } else { echo json_encode(['error' => 'Fehler beim Löschen: ' . mysqli_error($GLOBALS['mysql_con'])]); } exit; } /** * Löscht alle bestehenden Kategorie-Zuordnungen in der Tabelle knowledgecenter_category_post * für den gegebenen Post und fügt dann für jede ausgewählte Kategorie einen neuen Eintrag ein. */ function update_post_categories() { // post_id und die Kategorien-IDs auslesen (als JSON-codiertes Array) $postId = (int) ($_POST['post_id'] ?? 0); $categoriesJson = $_POST['categories'] ?? '[]'; $categories = json_decode($categoriesJson, true); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } if (!is_array($categories)) { echo json_encode(['error' => 'Fehlerhafte Kategorien-Daten']); exit; } // Bestehende Einträge für diesen Beitrag löschen $deleteQuery = "DELETE FROM knowledgecenter_category_post WHERE post_id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { echo json_encode(['error' => 'Fehler beim Löschen alter Einträge: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } // Für jede ausgewählte Kategorie einen neuen Eintrag einfügen foreach ($categories as $catId) { $catId = (int) $catId; if ($catId > 0) { $insertQuery = "INSERT INTO knowledgecenter_category_post (post_id, category_id) VALUES ($postId, $catId)"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { echo json_encode(['error' => "Fehler beim Einfügen der Kategorie $catId: " . mysqli_error($GLOBALS['mysql_con'])]); exit; } } } echo json_encode(['success' => true]); exit; } function get_post_list() { $languageId = isset($_POST['language_id']) ? $_POST['language_id'] : '1'; $languageCode = isset($_POST['language_code']) ? $_POST['language_code'] : 'de'; $categoryId = isset($_POST['category_id']) ? (int) $_POST['category_id'] : 0; // Prüfe, ob ein redirectURL-Parameter übergeben wurde, sonst verwende $_SERVER['REQUEST_URI'] $passedRedirectURL = isset($_POST['redirectURL']) ? $_POST['redirectURL'] : $_SERVER['REQUEST_URI']; $redirectUrl = urlencode($passedRedirectURL); // Lese den Suchbegriff aus (optional) $search = ''; if (isset($_POST['query'])) { $search = mysqli_real_escape_string($GLOBALS['mysql_con'], $_POST['query']); } // Erstelle einen zusätzlichen Filter – wenn ein Suchbegriff vorhanden ist, filtere nach Titel ODER Kategorie if ($search) { $searchCondition = " AND ( pv.title LIKE '%$search%' OR EXISTS ( SELECT 1 FROM knowledgecenter_category_post AS cp JOIN knowledgecenter_category_translations AS t ON cp.category_id = t.category_id AND t.language_id = $languageId WHERE cp.post_id = kp.id AND t.title LIKE '%$search%' ) OR EXISTS ( SELECT 1 FROM knowledgecenter_post_versions AS kpv2 JOIN main_contact AS sc ON kpv2.author_id = sc.id WHERE kpv2.post_id = kp.id AND sc.name LIKE '%$search%' ) )"; } else { $searchCondition = ""; } if ($categoryId) { // nur Posts, die in dieser Kategorie sind $categoryCondition = " AND EXISTS ( SELECT 1 FROM knowledgecenter_category_post AS cp WHERE cp.post_id = kp.id AND cp.category_id = $categoryId )"; } else { $categoryCondition = ""; } // Beiträge abfragen (nur Post‑ID und Titel der aktuellen Version) $sqlPosts = " SELECT kp.id AS post_id, pv.title AS current_title FROM knowledgecenter_posts AS kp LEFT JOIN knowledgecenter_post_versions AS pv ON kp.id = pv.post_id AND pv.language_id = $languageId /* … Bedingungen für gültige Version und höchste version_number … */ WHERE 1=1 $searchCondition $categoryCondition GROUP BY kp.id ORDER BY kp.modified_at DESC "; $resPosts = mysqli_query($GLOBALS['mysql_con'], $sqlPosts); $count = ($resPosts) ? mysqli_num_rows($resPosts) : 0; $postsHtml = ''; $fmt = new IntlDateFormatter('de_DE', IntlDateFormatter::LONG, IntlDateFormatter::SHORT); if ($resPosts && mysqli_num_rows($resPosts) > 0) { $postsHtml .= "
Keine Versionen gefunden.
"; } $postsHtml .= "Keine Beiträge gefunden.
'; } echo json_encode([ 'success' => true, 'html' => $postsHtml, 'count' => (int)$count ]); exit; } /** * Löscht alte Mandanten-Verknüpfungen für einen Beitrag und fügt neue ein. */ function update_post_mandants($postId, $mandantIds) { // Alte Verknüpfungen löschen $deleteQuery = "DELETE FROM knowledgecenter_post_mandant WHERE post_id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Post-Mandanten-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } // Neue Verknüpfungen einfügen foreach ($mandantIds as $mandantId) { $mandantId = (int) $mandantId; $insertQuery = "INSERT INTO knowledgecenter_post_mandant (post_id, mandant_id, created_at) VALUES ($postId, $mandantId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Mandant-ID $mandantId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Department-Verknüpfungen für einen Beitrag und fügt neue ein. */ function update_post_departments($postId, $departmentIds) { $deleteQuery = "DELETE FROM knowledgecenter_post_department WHERE post_id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Post-Department-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } foreach ($departmentIds as $departmentId) { $departmentId = (int) $departmentId; $insertQuery = "INSERT INTO knowledgecenter_post_department (post_id, department_id, created_at) VALUES ($postId, $departmentId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Department-ID $departmentId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Rollen-Verknüpfungen für einen Beitrag und fügt neue ein. */ function update_post_roles($postId, $roleIds) { $deleteQuery = "DELETE FROM knowledgecenter_post_role WHERE post_id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Post-Rollen-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } foreach ($roleIds as $roleId) { $roleId = (int) $roleId; $insertQuery = "INSERT INTO knowledgecenter_post_role (post_id, role_id, created_at) VALUES ($postId, $roleId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Rollen-ID $roleId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Einrichtungs-Verknüpfungen für einen Beitrag und fügt neue ein. */ function update_post_einrichts($postId, $einrichtIds) { $deleteQuery = "DELETE FROM knowledgecenter_post_einricht WHERE post_id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Post-Einrichtungs-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } foreach ($einrichtIds as $einrichtId) { $einrichtId = (int) $einrichtId; $insertQuery = "INSERT INTO knowledgecenter_post_einricht (post_id, einricht_id, created_at) VALUES ($postId, $einrichtId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Einrichtungs-ID $einrichtId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Fachbereich-Verknüpfungen für einen Beitrag und fügt neue ein. */ function update_post_fachbereiche($postId, $fachbereichIds) { $deleteQuery = "DELETE FROM knowledgecenter_post_fachbereich WHERE post_id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Post-Fachbereich-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } foreach ($fachbereichIds as $fachbereichId) { $fachbereichId = (int) $fachbereichId; $insertQuery = "INSERT INTO knowledgecenter_post_fachbereich (post_id, fachbereich_id, created_at) VALUES ($postId, $fachbereichId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Fachbereich-ID $fachbereichId: " . mysqli_error($GLOBALS['mysql_con']); } } return true; } /** * Löscht alte Produkt-Verknüpfungen und fügt neue in product_knowledgecenter_post_link ein. */ function update_post_products($postId, $productIds) { // Alte Verknüpfungen löschen $deleteQuery = "DELETE FROM product_knowledgecenter_post_link WHERE post_id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { return "Fehler beim Löschen der Produkt-Verknüpfungen: " . mysqli_error($GLOBALS['mysql_con']); } // Neue Verknüpfungen einfügen foreach ($productIds as $productId) { $productId = (int) $productId; if ($productId > 0) { $insertQuery = " INSERT INTO product_knowledgecenter_post_link (product_id, post_id) VALUES ($productId, $postId) "; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { return "Fehler beim Einfügen der Produkt-ID $productId: " . mysqli_error($GLOBALS['mysql_con']); } } } return true; } function save_post_files() { $postId = (int) ($_POST['post_id'] ?? 0); $filesStr = trim($_POST['post_files'] ?? ''); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } if (!ajax_can_edit_post($postId)) { echo json_encode(['error' => 'Keine Berechtigung']); exit; } if (!empty($filesStr)) { // Zerlege den String in einzelne Pfade (getrennt durch Komma und optional Leerzeichen) $files = preg_split('/,\s*/', $filesStr); $errors = []; foreach ($files as $file) { $file = trim($file); if (empty($file)) { continue; } // Setze die Beschreibung standardmäßig auf den Dateinamen, // der letzte Teil des Pfades (mithilfe von basename) $description = basename($file); // Füge "/userdata/" vor dem Dateipfad hinzu // Mit ltrim entfernen wir einen eventuell vorhandenen führenden Slash $fileWithPrefix = '/userdata/' . ltrim($file, '/'); // Pfad sicher escapen $escapedFile = mysqli_real_escape_string($GLOBALS['mysql_con'], $fileWithPrefix); $query = "INSERT INTO knowledgecenter_post_files (post_id, description, path, created_at) VALUES ($postId, '$description', '$escapedFile', NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $query)) { $errors[] = mysqli_error($GLOBALS['mysql_con']); } } if (!empty($errors)) { echo json_encode(['error' => implode("; ", $errors)]); exit; } } echo json_encode(['success' => true]); exit; } function get_post_files() { $postId = (int) ($_POST['post_id'] ?? 0); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Post-ID']); exit; } $query = "SELECT id, description, path FROM knowledgecenter_post_files WHERE post_id = $postId ORDER BY created_at ASC"; $result = mysqli_query($GLOBALS['mysql_con'], $query); if (!$result) { echo json_encode(['error' => 'Datenbankfehler: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $files = []; while ($row = mysqli_fetch_assoc($result)) { $files[] = $row; } echo json_encode(['success' => true, 'files' => $files]); exit; } function delete_post_file() { $fileId = (int) ($_POST['file_id'] ?? 0); if ($fileId <= 0) { echo json_encode(['error' => 'Ungültige Datei-ID']); exit; } $selectQuery = "SELECT path, post_id FROM knowledgecenter_post_files WHERE id = $fileId LIMIT 1"; $selectResult = mysqli_query($GLOBALS['mysql_con'], $selectQuery); if (!$selectResult || mysqli_num_rows($selectResult) === 0) { echo json_encode(['error' => 'Datei-Eintrag nicht gefunden']); exit; } $row = mysqli_fetch_assoc($selectResult); $storedPath = trim((string) ($row['path'] ?? '')); if (!ajax_can_edit_post((int)($row['post_id'] ?? 0))) { echo json_encode(['error' => 'Keine Berechtigung']); exit; } $userdataRoot = realpath($_SERVER['DOCUMENT_ROOT'] . '/userdata'); if ($userdataRoot === false) { echo json_encode(['error' => 'userdata-Verzeichnis nicht gefunden']); exit; } $relativePath = ltrim(str_replace('\\', '/', $storedPath), '/'); if (strpos($relativePath, 'userdata/') === 0) { $relativePath = substr($relativePath, strlen('userdata/')); } if ($relativePath === '' || strpos($relativePath, '..') !== false) { echo json_encode(['error' => 'Ungültiger Dateipfad']); exit; } $absolutePath = $userdataRoot . '/' . $relativePath; $absoluteDir = realpath(dirname($absolutePath)); if ($absoluteDir === false || strpos($absoluteDir, $userdataRoot) !== 0) { echo json_encode(['error' => 'Ungültiges Zielverzeichnis']); exit; } if (is_file($absolutePath)) { if (!@unlink($absolutePath)) { echo json_encode(['error' => 'Datei konnte nicht vom Server gelöscht werden']); exit; } } $deleteQuery = "DELETE FROM knowledgecenter_post_files WHERE id = $fileId"; if (mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { echo json_encode(['success' => true]); } else { echo json_encode(['error' => 'Fehler beim Löschen des Datenbankeintrags: ' . mysqli_error($GLOBALS['mysql_con'])]); } exit; } /** * Aktualisiert die Kontakte (Ansprechpartner) eines Beitrags in der Tabelle knowledgecenter_post_contacts. */ function update_post_contacts() { // Hole die Post-ID und dekodiere den JSON-String für Ansprechpartner $postId = (int) ($_POST['post_id'] ?? 0); $contactIds = json_decode($_POST['contacts'] ?? '[]', true) ?: []; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } // Lösche alle bestehenden Kontakte für diesen Beitrag $deleteQuery = "DELETE FROM knowledgecenter_post_contacts WHERE post_id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $deleteQuery)) { echo json_encode(['error' => 'Fehler beim Löschen bestehender Kontakte: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $errors = []; // Füge jeden angegebenen Ansprechpartner ein foreach ($contactIds as $contactId) { $contactId = (int) $contactId; if ($contactId > 0) { $insertQuery = "INSERT INTO knowledgecenter_post_contacts (post_id, main_contact_id, created_at) VALUES ($postId, $contactId, NOW())"; if (!mysqli_query($GLOBALS['mysql_con'], $insertQuery)) { $errors[] = "Fehler beim Einfügen der Kontakt-ID $contactId: " . mysqli_error($GLOBALS['mysql_con']); } } } if (!empty($errors)) { echo json_encode(['error' => implode("; ", $errors)]); exit; } echo json_encode(['success' => true]); exit; } /** * Gibt als HTML-String Visitenkarten der zugeordneten Kontakte zurück. */ function get_contact_cards() { $postId = (int) ($_POST['post_id'] ?? 0); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } // Erweiterte Abfrage: Lade zusätzlich email und image $query = "SELECT mc.id, mc.name, mc.email, mc.image FROM knowledgecenter_post_contacts AS pc JOIN main_contact AS mc ON pc.main_contact_id = mc.id WHERE pc.post_id = $postId"; $result = mysqli_query($GLOBALS['mysql_con'], $query); if (!$result) { echo json_encode(['error' => 'Datenbankfehler: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $html = ''; // Erstelle die HTML-Struktur für jeden Kontakt while ($row = mysqli_fetch_assoc($result)) { // Link zum Profil – passe den Pfad an, falls nötig $profileLink = "/intranet/de/profil/?contact=" . $row['id']; // Falls kein Bild vorhanden, verwende einen Platzhalter $image = !empty($row['image']) ? '/userdata/intranet/contact/' . $row['image'] : '/userdata/intranet/contact/default_avatar.webp'; $name = htmlspecialchars($row['name']); $email = htmlspecialchars($row['email']); $html .= ''; $html .= '' . $email . '
'; $html .= 'Keine passenden Beiträge gefunden.
'; } echo json_encode([ 'success' => true, 'html' => $html ]); exit; } /** * Aktualisiert in der Tabelle main_certificate für ein gegebenes Zertifikat den zugeordneten post_id-Wert. * Falls kein Zertifikat ausgewählt wurde (certificate_id leer oder 0), wird die Zuordnung entfernt, * indem alle Zertifikate, die aktuell diesen Beitrag zugeordnet haben, auf NULL gesetzt werden. * * Erwartete POST-Parameter: * - post_id: Die ID des Beitrags, der dem Zertifikat zugewiesen werden soll. * - certificate_id: Die ID des Zertifikats, dessen post_id gesetzt werden soll oder leer/0, um die Zuordnung zu entfernen. * * @return void JSON-Antwort mit Erfolgsmeldung oder Fehler */ function update_post_certificate() { // Beitrags-ID extrahieren und in Integer umwandeln $postId = (int) ($_POST['post_id'] ?? 0); // certificate_id auswerten: Falls ein leerer Wert oder 0, gilt dies als "kein Zertifikat ausgewählt" $certificateId = isset($_POST['certificate_id']) && $_POST['certificate_id'] !== "" ? (int) ($_POST['certificate_id']) : 0; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } // Falls eine gültige certificate_id übergeben wurde (größer als 0) if ($certificateId > 0) { // Dem Zertifikat wird der Beitrag zugeordnet $query = "UPDATE main_certificate SET post_id = $postId WHERE id = $certificateId"; if (mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['success' => true]); } else { echo json_encode(['error' => 'Fehler beim Aktualisieren des Zertifikats: ' . mysqli_error($GLOBALS['mysql_con'])]); } } else { // Kein Zertifikat ausgewählt – entferne die Zuordnung zu diesem Beitrag $query = "UPDATE main_certificate SET post_id = NULL WHERE post_id = $postId"; if (mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['success' => true, 'message' => 'Zertifikats-Zuordnung entfernt']); } else { echo json_encode(['error' => 'Fehler beim Entfernen der Zertifikats-Zuordnung: ' . mysqli_error($GLOBALS['mysql_con'])]); } } exit; } function update_post_pdf_inline() { $postId = (int) ($_POST['post_id'] ?? 0); // Wenn der Parameter pdf_inline im POST gesetzt ist, wird der Wert verwendet, ansonsten 0 $pdfInline = isset($_POST['pdf_inline']) ? (int) $_POST['pdf_inline'] : 0; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } $query = "UPDATE knowledgecenter_posts SET preview_inline = $pdfInline WHERE id = $postId"; if (mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['success' => true]); } else { echo json_encode(['error' => 'Fehler beim Aktualisieren der PDF Inline Vorschau: ' . mysqli_error($GLOBALS['mysql_con'])]); } exit; } function update_post_colors() { $postId = (int) ($_POST['post_id'] ?? 0); if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } $backgroundColor = normalize_hex_color($_POST['background_color'] ?? '#FFFFFF', '#FFFFFF'); $textColor = normalize_hex_color($_POST['text_color'] ?? '#000000', '#000000'); $query = "UPDATE knowledgecenter_posts SET background_color = '$backgroundColor', text_color = '$textColor', modified_at = NOW() WHERE id = $postId"; if (mysqli_query($GLOBALS['mysql_con'], $query)) { echo json_encode(['success' => true]); } else { echo json_encode(['error' => 'Fehler beim Aktualisieren der Post-Farben: ' . mysqli_error($GLOBALS['mysql_con'])]); } exit; } /** * Löscht einen kompletten Beitrag (inkl. all seiner Versionen). */ function delete_post() { $postId = isset($_POST['post_id']) ? (int) $_POST['post_id'] : 0; if ($postId <= 0) { echo json_encode(['error' => 'Ungültige Beitrags-ID']); exit; } // 2) Haupt-Datensatz löschen $delPostQ = "DELETE FROM knowledgecenter_posts WHERE id = $postId"; if (!mysqli_query($GLOBALS['mysql_con'], $delPostQ)) { echo json_encode(['error' => 'Fehler beim Löschen des Beitrags: ' . mysqli_error($GLOBALS['mysql_con'])]); exit; } $deleteFolderResult = delete_post_gallery_dir($postId); if (!$deleteFolderResult['success']) { echo json_encode(['error' => 'Beitrag gelöscht, aber Ordner konnte nicht gelöscht werden: ' . $deleteFolderResult['error']]); exit; } echo json_encode(['success' => true]); exit; } ?>