- Migrationsskript: Teaser/Content getrennt (kc_teaser id=55 → teaser, kc_article id=58 → content), Gemini-Summaries mit thinkingBudget=0, Retry-Logik für 503/429-Fehler - Berechtigungsfehler behoben: AND active=1 aus main_contact_department- Abfrage entfernt (Middleware + Ajax) - Kategoriebeschreibungen: neues description-Feld in knowledgecenter_category_translations, aus kc.tags befüllt - Kacheln: Hauptebene erhält post_wiki-Klasse für einheitliches Design, Beschreibungstext in Grid-Ansicht, in Listenansicht ausgeblendet - Buttons: Beitrag-erstellen nutzt --clr-mandant, alle vier Toolbar- Buttons auf gleiche Höhe normiert (line-height: 1 + SVG 1em) - Platzhalterpfade für Kategorien und Beiträge korrigiert - Zusammenfassung in Beitragsansicht angezeigt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2143 lines
84 KiB
PHP
2143 lines
84 KiB
PHP
<?php
|
||
// ini_set('display_errors', 1);
|
||
// error_reporting(E_ALL);
|
||
|
||
$currDir = __DIR__;
|
||
$rootDir = dirname(dirname(dirname($currDir)));
|
||
$mysydeDir = $rootDir . '/mysyde';
|
||
|
||
require_once($rootDir . '/vendor/autoload.php');
|
||
require_once($rootDir . "/mysyde/frontend/frontend_functions.inc.php");
|
||
|
||
$envDir = $rootDir . '/config';
|
||
$envFilePath = $envDir . '/.env';
|
||
if (is_dir($envDir) && file_exists($envFilePath) && is_file($envFilePath) && is_readable($envFilePath)) {
|
||
$dotenv = new \Dotenv\Dotenv($envDir);
|
||
$dotenv->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();
|
||
|
||
// 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;
|
||
$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,
|
||
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 .= "<div class='posts-container'>";
|
||
while ($row = mysqli_fetch_assoc($resPosts)) {
|
||
$postId = $row['post_id'];
|
||
$postTitle = htmlspecialchars($row['current_title'] ?: 'Kein Titel');
|
||
// Kategorien holen
|
||
$catTitles = [];
|
||
$sqlCat = "
|
||
SELECT t.title
|
||
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 = $postId
|
||
";
|
||
$resCat = mysqli_query($GLOBALS['mysql_con'], $sqlCat);
|
||
if ($resCat) {
|
||
while ($c = mysqli_fetch_assoc($resCat)) {
|
||
$catTitles[] = htmlspecialchars($c['title']);
|
||
}
|
||
}
|
||
|
||
// URL zum Post
|
||
$postUrl = "?action=Post&id={$postId}&language=" . urlencode($languageCode)
|
||
. "&redirectURL={$redirectUrl}";
|
||
|
||
// 1) Post-Überschrift & klickbare Container-Div
|
||
$postsHtml .= "<div class='post-item' style='cursor:pointer;' onclick=\"window.location.href='{$postUrl}'\">";
|
||
// Titel + Kategorien
|
||
$postsHtml .= "<div class='post-item-title'>{$postTitle}";
|
||
if (!empty($catTitles)) {
|
||
$postsHtml .= "<div class='category-list'>";
|
||
foreach ($catTitles as $catName) {
|
||
$postsHtml .= "<small class='category-item'>{$catName}</small>";
|
||
}
|
||
$postsHtml .= "</div>";
|
||
}
|
||
$postsHtml .= "</div>"; // Ende post-item-title
|
||
|
||
// 2) Versionen-Liste
|
||
$sqlVers = "
|
||
SELECT
|
||
kpv.version_number,
|
||
kpv.title,
|
||
kpv.modified_at,
|
||
kpv.state,
|
||
sc.name AS author
|
||
FROM knowledgecenter_post_versions AS kpv
|
||
LEFT JOIN main_contact AS sc
|
||
ON kpv.author_id = sc.id
|
||
WHERE kpv.post_id = $postId
|
||
AND kpv.language_id = $languageId
|
||
ORDER BY kpv.version_number DESC
|
||
";
|
||
$resVers = mysqli_query($GLOBALS['mysql_con'], $sqlVers);
|
||
|
||
if ($resVers && mysqli_num_rows($resVers) > 0) {
|
||
$postsHtml .= "<ul class='version-list'>";
|
||
while ($v = mysqli_fetch_assoc($resVers)) {
|
||
$isActive = ((int) $v['state'] === 1);
|
||
$statusClass = $isActive ? 'active' : 'inactive';
|
||
$verState = " <span class='status {$statusClass}'></span>";
|
||
$verNum = (int) $v['version_number'];
|
||
$verTitle = htmlspecialchars($v['title'] ?: '– kein Titel –');
|
||
$verDate = $v['modified_at']
|
||
? $fmt->format(strtotime($v['modified_at']))
|
||
: '-';
|
||
$author = htmlspecialchars($v['author'] ?: 'Unbekannt');
|
||
|
||
$postsHtml .=
|
||
"<li>
|
||
<div>
|
||
{$verState} Version {$verNum}: {$verTitle}
|
||
</div>
|
||
<small>geändert am {$verDate} von {$author}</small>
|
||
</li>";
|
||
}
|
||
$postsHtml .= "</ul>";
|
||
} else {
|
||
$postsHtml .= "<p><em>Keine Versionen gefunden.</em></p>";
|
||
}
|
||
|
||
$postsHtml .= "</div>"; // Ende .post-item
|
||
}
|
||
$postsHtml .= "</div>"; // Ende .posts-container
|
||
} else {
|
||
$postsHtml = '<p>Keine Beiträge gefunden.</p>';
|
||
}
|
||
|
||
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 (!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 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'] ?? ''));
|
||
|
||
$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 .= '<a href="' . $profileLink . '" class="contact-card">';
|
||
$html .= ' <div class="contact-image">';
|
||
$html .= ' <img src="' . $image . '" alt="Profilbild von ' . $name . '">';
|
||
$html .= ' </div>';
|
||
$html .= ' <div class="contact-details">';
|
||
$html .= ' <h3>' . $name . '</h3>';
|
||
$html .= ' <p>' . $email . '</p>';
|
||
$html .= ' </div>';
|
||
$html .= '</a>';
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'html' => $html]);
|
||
exit;
|
||
}
|
||
|
||
function search_posts()
|
||
{
|
||
// Parameter-Verarbeitung
|
||
$languageCode = $_POST['language_code'] ?? 'de';
|
||
$languageId = $_POST['language'] ?? '1';
|
||
$queryText = trim($_POST['query'] ?? '');
|
||
$page = isset($_POST['page']) ? (int) $_POST['page'] : 1;
|
||
$limit = 50;
|
||
$offset = ($page - 1) * $limit;
|
||
$limitPlusOne = $limit + 1; // um zusätzlich eine Zeile zu laden, falls mehr Ergebnisse existieren
|
||
|
||
/**
|
||
* Zunächst: Holen der User-Daten (Mandanten, Abteilungen, Rollen, Einrichtungen, Fachbereiche)
|
||
*/
|
||
$currentUserId = $_POST["main_contact_id"] ?? 0;
|
||
$userMandants = [];
|
||
$userDepartments = [];
|
||
$userRoles = [];
|
||
$userEinrichts = [];
|
||
$userFachbereiche = [];
|
||
|
||
if ($currentUserId) {
|
||
$query = "SELECT main_mandant_id, main_department_id, main_role_id, main_einricht_id, main_bereich_id
|
||
FROM main_contact_department
|
||
WHERE main_contact_id = $currentUserId";
|
||
$result = mysqli_query($GLOBALS['mysql_con'], $query);
|
||
while ($row = mysqli_fetch_assoc($result)) {
|
||
// Filtere 0 aus – 0 gilt als "keine Zuordnung"
|
||
if ($row['main_mandant_id'] != 0 && !in_array($row['main_mandant_id'], $userMandants)) {
|
||
$userMandants[] = $row['main_mandant_id'];
|
||
}
|
||
if ($row['main_department_id'] != 0 && !in_array($row['main_department_id'], $userDepartments)) {
|
||
$userDepartments[] = $row['main_department_id'];
|
||
}
|
||
if ($row['main_role_id'] != 0 && !in_array($row['main_role_id'], $userRoles)) {
|
||
$userRoles[] = $row['main_role_id'];
|
||
}
|
||
if ($row['main_einricht_id'] != 0 && !in_array($row['main_einricht_id'], $userEinrichts)) {
|
||
$userEinrichts[] = $row['main_einricht_id'];
|
||
}
|
||
if ($row['main_bereich_id'] != 0 && !in_array($row['main_bereich_id'], $userFachbereiche)) {
|
||
$userFachbereiche[] = $row['main_bereich_id'];
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Für den LEFT JOIN-Ansatz bereiten wir die erlaubten Werte als
|
||
* kommaseparierte Strings vor.
|
||
*/
|
||
$allowedMandants = !empty($userMandants) ? implode(',', $userMandants) : 'NULL';
|
||
$allowedDepartments = !empty($userDepartments) ? implode(',', $userDepartments) : 'NULL';
|
||
$allowedRoles = !empty($userRoles) ? implode(',', $userRoles) : 'NULL';
|
||
$allowedEinrichts = !empty($userEinrichts) ? implode(',', $userEinrichts) : 'NULL';
|
||
$allowedFachbereiche = !empty($userFachbereiche) ? implode(',', $userFachbereiche) : 'NULL';
|
||
|
||
|
||
|
||
|
||
// Suchbedingung: Auf title, teaser, content
|
||
$safeQuery = mysqli_real_escape_string($GLOBALS['mysql_con'], $queryText);
|
||
$searchCondition = "";
|
||
if ($safeQuery) {
|
||
$searchCondition = "AND (
|
||
pv.title LIKE '%$safeQuery%' OR
|
||
pv.teaser LIKE '%$safeQuery%' OR
|
||
pv.content LIKE '%$safeQuery%'
|
||
)";
|
||
}
|
||
|
||
// Hier bauen wir den Query mithilfe von LEFT JOINs:
|
||
// Wir joinen zunächst die Tabelle der Posts mit den Versionen (wie gehabt).
|
||
// Anschließend werden die Filtertabellen (Abteilung, Mandant, Rolle) via LEFT JOIN angehängt.
|
||
// In der WHERE-Klausel stellen wir sicher, dass in jedem dieser Bereiche entweder kein Datensatz
|
||
// vorliegt (NULL) oder der Wert in den erlaubten Werten enthalten ist.
|
||
$sql = "
|
||
SELECT DISTINCT
|
||
kp.id AS post_id,
|
||
kp.modified_at,
|
||
pv.title,
|
||
pv.image,
|
||
pv.teaser,
|
||
pv.content,
|
||
(
|
||
SELECT GROUP_CONCAT(mc.name SEPARATOR ', ')
|
||
FROM knowledgecenter_post_contacts AS pc
|
||
JOIN main_contact AS mc ON mc.id = pc.main_contact_id
|
||
WHERE pc.post_id = kp.id
|
||
) AS contacts,
|
||
(
|
||
SELECT GROUP_CONCAT(t.title SEPARATOR ', ')
|
||
FROM knowledgecenter_category_post AS cp
|
||
JOIN knowledgecenter_category_translations AS t
|
||
ON cp.category_id = t.category_id
|
||
WHERE cp.post_id = kp.id AND t.language_id = $languageId
|
||
) AS categories
|
||
FROM knowledgecenter_posts AS kp
|
||
LEFT JOIN knowledgecenter_post_versions AS pv
|
||
ON kp.id = pv.post_id
|
||
AND pv.language_id = $languageId
|
||
AND pv.state = 1
|
||
AND (pv.valid_from IS NULL OR pv.valid_from <= NOW())
|
||
AND (pv.valid_until IS NULL OR pv.valid_until >= NOW())
|
||
AND pv.version_number = (
|
||
SELECT MAX(version_number)
|
||
FROM knowledgecenter_post_versions
|
||
WHERE post_id = kp.id
|
||
AND language_id = $languageId
|
||
AND (valid_from IS NULL OR valid_from <= NOW())
|
||
AND (valid_until IS NULL OR valid_until >= NOW())
|
||
)
|
||
LEFT JOIN knowledgecenter_post_department AS pd
|
||
ON kp.id = pd.post_id
|
||
LEFT JOIN knowledgecenter_post_mandant AS pm
|
||
ON kp.id = pm.post_id
|
||
LEFT JOIN knowledgecenter_post_role AS pr
|
||
ON kp.id = pr.post_id
|
||
LEFT JOIN knowledgecenter_post_einricht AS pe
|
||
ON kp.id = pe.post_id
|
||
LEFT JOIN knowledgecenter_post_fachbereich AS pfb
|
||
ON kp.id = pfb.post_id
|
||
WHERE 1=1
|
||
$searchCondition
|
||
AND ( pd.department_id IS NULL OR pd.department_id IN ($allowedDepartments) )
|
||
AND ( pm.mandant_id IS NULL OR pm.mandant_id IN ($allowedMandants) )
|
||
AND ( pr.role_id IS NULL OR pr.role_id IN ($allowedRoles) )
|
||
AND ( pe.einricht_id IS NULL OR pe.einricht_id IN ($allowedEinrichts) )
|
||
AND ( pfb.fachbereich_id IS NULL OR pfb.fachbereich_id IN ($allowedFachbereiche) )
|
||
ORDER BY kp.modified_at DESC
|
||
LIMIT $offset, $limitPlusOne
|
||
";
|
||
|
||
|
||
|
||
$result = mysqli_query($GLOBALS['mysql_con'], $sql);
|
||
$html = '';
|
||
|
||
// Ergebnisse in ein Array übernehmen
|
||
$rows = [];
|
||
if ($result && mysqli_num_rows($result) > 0) {
|
||
while ($row = mysqli_fetch_assoc($result)) {
|
||
$rows[] = $row;
|
||
}
|
||
}
|
||
// Wenn mehr als $limit Ergebnisse gefunden wurden, dann gibt es weitere Seiten.
|
||
$hasMore = (count($rows) > $limit);
|
||
if ($hasMore) {
|
||
array_pop($rows); // letztes Element entfernen
|
||
}
|
||
|
||
// Ergebnisse rendern
|
||
if (count($rows) > 0) {
|
||
$fmt = new IntlDateFormatter('de_DE', IntlDateFormatter::LONG, IntlDateFormatter::SHORT);
|
||
$highlight = function ($text, $query) {
|
||
if (!$query)
|
||
return htmlspecialchars($text);
|
||
return preg_replace_callback(
|
||
"/" . preg_quote($query, "/") . "/i",
|
||
function ($match) {
|
||
return "<mark>{$match[0]}</mark>";
|
||
},
|
||
htmlspecialchars($text)
|
||
);
|
||
};
|
||
|
||
$html .= '<ul class="search-list">';
|
||
foreach ($rows as $row) {
|
||
$title = $highlight($row['title'] ?: 'Kein Titel', $queryText);
|
||
$teaser = $highlight($row['teaser'], $queryText);
|
||
$content = strip_tags($row['content']);
|
||
if (!$teaser && $queryText) {
|
||
if (stripos($content, $queryText) !== false) {
|
||
$pos = stripos($content, $queryText);
|
||
$snippet = substr($content, max(0, $pos - 30), 100);
|
||
$teaser = $highlight("…{$snippet}…", $queryText);
|
||
}
|
||
}
|
||
$img = !empty($row['image']) ? '/userdata/' . htmlspecialchars($row['image']) : '/userdata/knowledgecenter_update/platzhalter.jpg';
|
||
$link = "?action=Post&id={$row['post_id']}&language={$languageCode}";
|
||
|
||
// Kontakte
|
||
$contacts = $row['contacts'] ?? '';
|
||
$personSVG = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
|
||
<path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0"/>
|
||
<path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1"/>
|
||
</svg>';
|
||
$contactsHtml = $contacts ? "<small class='contacts'>$personSVG " . htmlspecialchars($contacts) . "</small><br>" : "";
|
||
|
||
// Kategorien als einzelne kleine Elemente in einem div
|
||
$categoriesHtml = "";
|
||
if (!empty($row['categories'])) {
|
||
// Den zurückgegebenen String in ein Array aufspalten
|
||
$catArray = explode(', ', $row['categories']);
|
||
$categoriesHtml .= "<div class='categories'>";
|
||
foreach ($catArray as $cat) {
|
||
$categoriesHtml .= "<small class='category-item'>" . htmlspecialchars($cat) . "</small> ";
|
||
}
|
||
$categoriesHtml .= "</div>";
|
||
}
|
||
|
||
$html .= "<li class='search-item'>
|
||
<a href='{$link}'>
|
||
<img src='{$img}' alt='Bild'>
|
||
<div>
|
||
<strong>{$title}</strong><br>
|
||
{$contactsHtml}
|
||
<small>{$teaser}</small><br>
|
||
{$categoriesHtml}
|
||
</div>
|
||
</a>
|
||
</li>";
|
||
}
|
||
$html .= '</ul>';
|
||
|
||
if ($hasMore) {
|
||
$nextPage = $page + 1;
|
||
$html .= "<button id='loadMoreBtn' data-page='{$nextPage}'>Weitere Ergebnisse laden</button>";
|
||
}
|
||
} else {
|
||
$html = '<p>Keine passenden Beiträge gefunden.</p>';
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
?>
|
||
|
||
<!-- <script src="/plugins/fslightbox/fslightbox.js">
|
||
</script> -->
|