Neue Permission r-wiki-br ermöglicht eingeschränkte Wiki-Bearbeitung: - Neue Permission in main_permission (ID 30: r-wiki-br) - Neue Spalte betriebsrat_editable in knowledgecenter_categories_update - Checkbox "Für Betriebsrat bearbeitbar" in der Kategorie-Verwaltung (nur für r-wiki-Redakteure sichtbar und speicherbar) Berechtigungslogik: - r-wiki schlägt immer: Wer beide Rechte hat, verhält sich wie Redakteur - Betriebsrat sieht nur Kategorien mit betriebsrat_editable=1 - "Beitrag erstellen"-Button nur in freigegebenen Kategorien sichtbar - Neue Posts/Bearbeitungen auf betriebsrat_editable-Kategorien beschränkt - Settings-Tab und Kategorieverwaltung weiterhin r-wiki-only - Ajax-Endpoints (save_post_files, delete_post_file, upload_inline_image) prüfen Kategorie-Berechtigung serverseitig File Gallery: - Betriebsrat ist per kc_lock_path auf den Post-eigenen Ordner beschränkt - Redakteur kann frei navigieren (kein Lock) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
166 lines
5.3 KiB
PHP
166 lines
5.3 KiB
PHP
<?php
|
|
/**
|
|
* Inline-Image-Upload für Quill im Wiki-Editor.
|
|
* Wird vom imageHandler in post_cardform.php aufgerufen.
|
|
*
|
|
* Erwartet (multipart/form-data POST):
|
|
* - file : Hochgeladenes Bild (jpg/png/gif/webp, <= 5 MB)
|
|
* - post_id : int > 0 (knowledgecenter_posts.id)
|
|
*
|
|
* Antwort (JSON):
|
|
* { "success": true, "url": "/userdata/knowledgecenter_update/posts/<hash>/inline/<sha>.<ext>" }
|
|
* { "success": false, "error": "..." } (HTTP 4xx/5xx)
|
|
*/
|
|
|
|
session_start();
|
|
|
|
$currDir = __DIR__;
|
|
$rootDir = dirname(dirname(dirname(dirname($currDir))));
|
|
$mysydeDir = $rootDir . '/mysyde';
|
|
|
|
require_once($rootDir . '/vendor/autoload.php');
|
|
require_once($mysydeDir . '/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();
|
|
}
|
|
|
|
require_once($mysydeDir . '/common/common_functions.inc.php');
|
|
|
|
$connEnv = (local_environment()) ? $mysydeDir . '/dc.config.php' : $mysydeDir . '/dc-server.config.php';
|
|
require_once($connEnv);
|
|
|
|
db_connect();
|
|
|
|
require_once($rootDir . '/module/intranet/intranet_functions.inc.php');
|
|
|
|
header('Content-Type: application/json');
|
|
|
|
function respond_error($msg, $code = 400)
|
|
{
|
|
http_response_code($code);
|
|
echo json_encode(['success' => false, 'error' => $msg]);
|
|
exit;
|
|
}
|
|
|
|
if (empty($_SESSION['login_id'])) {
|
|
respond_error('Nicht angemeldet.', 401);
|
|
}
|
|
$loginId = (int) $_SESSION['login_id'];
|
|
|
|
$q = mysqli_query($GLOBALS['mysql_con'], "SELECT id, master_mandant_id FROM main_contact WHERE id = $loginId LIMIT 1");
|
|
if (!$q || !($contactRow = mysqli_fetch_assoc($q))) {
|
|
respond_error('Benutzer nicht gefunden.', 401);
|
|
}
|
|
$contactId = (int) $contactRow['id'];
|
|
$masterMandantId = (int) $contactRow['master_mandant_id'];
|
|
|
|
$hasRwiki = get_permission_state('r-wiki', $masterMandantId, $contactId) == 1;
|
|
$hasRwikiBr = get_permission_state('r-wiki-br', $masterMandantId, $contactId) == 1;
|
|
if (!$hasRwiki && !$hasRwikiBr) {
|
|
respond_error('Keine Berechtigung.', 403);
|
|
}
|
|
|
|
$postId = isset($_POST['post_id']) ? (int) $_POST['post_id'] : 0;
|
|
if ($postId <= 0) {
|
|
respond_error('Ungültige post_id.');
|
|
}
|
|
|
|
$verifyQ = mysqli_query($GLOBALS['mysql_con'], "SELECT id FROM knowledgecenter_posts WHERE id = $postId LIMIT 1");
|
|
if (!$verifyQ || mysqli_num_rows($verifyQ) === 0) {
|
|
respond_error('Beitrag existiert nicht.', 404);
|
|
}
|
|
|
|
// Betriebsrat darf Bilder nur in freigegebene Kategorien hochladen
|
|
if (!$hasRwiki && $hasRwikiBr) {
|
|
$brRes = 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");
|
|
$brRow = mysqli_fetch_assoc($brRes);
|
|
if (!$brRow || (int)$brRow['cnt'] === 0) {
|
|
respond_error('Keine Berechtigung für diesen Beitrag.', 403);
|
|
}
|
|
}
|
|
|
|
if (!isset($_FILES['file']) || !is_array($_FILES['file'])) {
|
|
respond_error('Keine Datei empfangen.');
|
|
}
|
|
$file = $_FILES['file'];
|
|
|
|
if ($file['error'] !== UPLOAD_ERR_OK) {
|
|
respond_error('Upload-Fehler (Code ' . (int) $file['error'] . ').');
|
|
}
|
|
|
|
$maxSize = 5 * 1024 * 1024;
|
|
if (!is_uploaded_file($file['tmp_name'])) {
|
|
respond_error('Ungültiger Upload.');
|
|
}
|
|
if ($file['size'] <= 0 || $file['size'] > $maxSize) {
|
|
respond_error('Datei zu groß oder leer (max 5 MB).');
|
|
}
|
|
|
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
|
$mime = $finfo ? finfo_file($finfo, $file['tmp_name']) : false;
|
|
if ($finfo) {
|
|
finfo_close($finfo);
|
|
}
|
|
|
|
$mimeToExt = [
|
|
'image/jpeg' => 'jpg',
|
|
'image/png' => 'png',
|
|
'image/gif' => 'gif',
|
|
'image/webp' => 'webp',
|
|
];
|
|
if (!$mime || !isset($mimeToExt[$mime])) {
|
|
respond_error('Ungültiger Dateityp. Erlaubt: JPG, PNG, GIF, WEBP.');
|
|
}
|
|
$ext = $mimeToExt[$mime];
|
|
|
|
$hash = substr(sha1('kc_post_' . $postId), 0, 24);
|
|
$relBase = 'knowledgecenter_update/posts/' . $hash;
|
|
$absBase = $rootDir . '/userdata/' . $relBase;
|
|
$absInline = $absBase . '/inline';
|
|
|
|
if (!is_dir($absBase) && !@mkdir($absBase, 0775, true)) {
|
|
respond_error('Post-Ordner konnte nicht erstellt werden.', 500);
|
|
}
|
|
$sharedLink = $absBase . '/shared';
|
|
if (!is_link($sharedLink) && !file_exists($sharedLink)) {
|
|
@symlink('../../shared', $sharedLink);
|
|
}
|
|
if (!is_dir($absInline) && !@mkdir($absInline, 0775, true)) {
|
|
respond_error('Inline-Ordner konnte nicht erstellt werden.', 500);
|
|
}
|
|
|
|
$sha = hash_file('sha256', $file['tmp_name']);
|
|
if (!$sha) {
|
|
respond_error('Hashing fehlgeschlagen.', 500);
|
|
}
|
|
$finalName = $sha . '.' . $ext;
|
|
$finalPath = $absInline . '/' . $finalName;
|
|
$publicUrl = '/userdata/' . $relBase . '/inline/' . $finalName;
|
|
|
|
if (file_exists($finalPath)) {
|
|
if (filesize($finalPath) === (int) $file['size']) {
|
|
echo json_encode(['success' => true, 'url' => $publicUrl, 'dedup' => true]);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
$tmpDest = $absInline . '/.tmp_' . bin2hex(random_bytes(6));
|
|
if (!move_uploaded_file($file['tmp_name'], $tmpDest)) {
|
|
respond_error('Datei konnte nicht gespeichert werden.', 500);
|
|
}
|
|
@chmod($tmpDest, 0664);
|
|
if (!rename($tmpDest, $finalPath)) {
|
|
@unlink($tmpDest);
|
|
respond_error('Datei konnte nicht verschoben werden.', 500);
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'url' => $publicUrl]);
|
|
exit;
|