Merge market document links
This commit is contained in:
commit
73e2144571
4 files changed
+102
-2
No files matched your search
@@ -22,6 +22,36 @@ Der Token wird nicht in dieser Dokumentation oder im Repository gespeichert.
|
|||||||
|
|
||||||
## Verbindungsablauf
|
## Verbindungsablauf
|
||||||
|
|
||||||
|
## Dokumentlinks in Marktdurchführungen
|
||||||
|
|
||||||
|
Wenn Hermes Informationen aus einer Datei verarbeitet und diese in einer
|
||||||
|
Marktdurchführung speichert, muss Hermes die Quelldatei als vollständige
|
||||||
|
HTTPS-URL in das Feld `notes` aufnehmen. Der bestehende Text darf erhalten
|
||||||
|
bleiben; die Position im Freitext ist frei wählbar.
|
||||||
|
|
||||||
|
Die URL verwendet dieses Format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://erpnaurua.imhochrain.ch/files.php?path=<RFC-3986-url-encodierter-relativer-Pfad>
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Parameter `path` ist relativ zum Ordner `Hermes Naurua` und enthält nicht
|
||||||
|
den lokalen Mount-Prefix und nicht den Ordnernamen `Hermes Naurua` selbst.
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Quelldatei: Hermes Naurua/Marktmanagement/2026 Bellevue Noël/Standmietvertrag_Naurua.pdf
|
||||||
|
Link: https://erpnaurua.imhochrain.ch/files.php?path=Marktmanagement%2F2026%20Bellevue%20No%C3%ABl%2FStandmietvertrag_Naurua.pdf
|
||||||
|
```
|
||||||
|
|
||||||
|
Leerzeichen, Umlaute und sonstige Sonderzeichen müssen vollständig URL-encodiert
|
||||||
|
werden. Die ERP-Anzeige macht ausschließlich diese Dokument-URLs klickbar. Der
|
||||||
|
Link ist schreibgeschützt und erfordert eine aktive ERP-Anmeldung.
|
||||||
|
|
||||||
|
Die Route benötigt auf dem ERP-Webserver die Konfiguration
|
||||||
|
`HERMES_DOCUMENT_ROOT=/volume1/Hermes/Hermes Naurua`. Dieser lokale Pfad ist
|
||||||
|
die auf DEV verifizierte Ablage der Synology-Freigabe.
|
||||||
|
|
||||||
## Fachliche Begrifflichkeit für Hermes
|
## Fachliche Begrifflichkeit für Hermes
|
||||||
|
|
||||||
Die fachliche Hierarchie lautet:
|
Die fachliche Hierarchie lautet:
|
||||||
|
|||||||
@@ -68,7 +68,10 @@ Modulberechtigung.
|
|||||||
- Fehlgeschlagene Aufrufe erzeugen keine Teilpersistierung.
|
- Fehlgeschlagene Aufrufe erzeugen keine Teilpersistierung.
|
||||||
- Alle Schreibvorgänge laufen über die interne Modul-API.
|
- Alle Schreibvorgänge laufen über die interne Modul-API.
|
||||||
- Hermes darf bei einem neuen Markt nur eine bestehende Kategorie referenzieren.
|
- Hermes darf bei einem neuen Markt nur eine bestehende Kategorie referenzieren.
|
||||||
- Dokumentlinks können optional als Herkunftsinformation mitgegeben werden.
|
- Wenn Hermes Informationen aus einer Datei verarbeitet und in einer
|
||||||
|
Marktdurchführung speichert, muss die Quelldatei als vollständige HTTPS-URL
|
||||||
|
im Feld `notes` referenziert werden. Die Position im bestehenden Freitext ist
|
||||||
|
frei wählbar.
|
||||||
- Unsichere Erkennung wird nicht durch eine zusätzliche App-Freigabelogik
|
- Unsichere Erkennung wird nicht durch eine zusätzliche App-Freigabelogik
|
||||||
behandelt; die fachliche Qualitätssicherung liegt im Hermes-Training.
|
behandelt; die fachliche Qualitätssicherung liegt im Hermes-Training.
|
||||||
|
|
||||||
|
|||||||
@@ -1152,7 +1152,7 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $otcM
|
|||||||
echo " const getCurrentLimit = () => parseInt(getTable()?.dataset.marketsLimit || '20', 10);";
|
echo " const getCurrentLimit = () => parseInt(getTable()?.dataset.marketsLimit || '20', 10);";
|
||||||
echo " const getPageSize = () => parseInt(getTable()?.dataset.marketsPageSize || '20', 10);";
|
echo " const getPageSize = () => parseInt(getTable()?.dataset.marketsPageSize || '20', 10);";
|
||||||
echo " const marketEscape = (value) => String(value ?? '').replace(/[&<>\"']/g, (character) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' }[character] || character));";
|
echo " const marketEscape = (value) => String(value ?? '').replace(/[&<>\"']/g, (character) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' }[character] || character));";
|
||||||
echo " const marketDisplay = (value) => value === null || value === undefined || value === '' ? 'Nicht hinterlegt' : marketEscape(value).replace(/\\r?\\n/g, '<br>');";
|
echo " const marketDisplay = (value) => { if (value === null || value === undefined || value === '') { return 'Nicht hinterlegt'; } const escaped = marketEscape(value); const linked = escaped.replace(/https:\\/\\/erpnaurua\\.imhochrain\\.ch\\/files\\.php\\?path=[^\\s<]+/g, (url) => '<a class=\"sg-hyperlink\" href=\"' + url + '\" target=\"_blank\" rel=\"noopener\">' + url + '</a>'); return linked.replace(/\\r?\\n/g, '<br>'); };";
|
||||||
echo " const marketBoolean = (value) => value === true || value === 'true' || value === 1 || value === '1' ? 'Ja' : value === false || value === 'false' || value === 0 || value === '0' ? 'Nein' : 'Nicht hinterlegt';";
|
echo " const marketBoolean = (value) => value === true || value === 'true' || value === 1 || value === '1' ? 'Ja' : value === false || value === 'false' || value === 0 || value === '0' ? 'Nein' : 'Nicht hinterlegt';";
|
||||||
echo " const marketMoney = (value) => value === null || value === undefined || value === '' ? 'Nicht hinterlegt' : 'CHF ' + Number(value).toFixed(2);";
|
echo " const marketMoney = (value) => value === null || value === undefined || value === '' ? 'Nicht hinterlegt' : 'CHF ' + Number(value).toFixed(2);";
|
||||||
echo " const marketContactName = (contact) => { if (!contact) { return 'Nicht hinterlegt'; } return marketDisplay([contact.first_name, contact.last_name].filter(Boolean).join(' ')); };";
|
echo " const marketContactName = (contact) => { if (!contact) { return 'Nicht hinterlegt'; } return marketDisplay([contact.first_name, contact.last_name].filter(Boolean).join(' ')); };";
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../modules/shared/db.php';
|
||||||
|
require_once __DIR__ . '/../modules/shared/auth/service.php';
|
||||||
|
|
||||||
|
$requestMethod = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
|
||||||
|
if ($requestMethod !== 'GET') {
|
||||||
|
http_response_code(405);
|
||||||
|
header('Allow: GET');
|
||||||
|
echo 'Methode nicht erlaubt.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$env = expand_env_values(parse_env_file(__DIR__ . '/../.env'));
|
||||||
|
$pdo = connect_database($env);
|
||||||
|
auth_bootstrap_session();
|
||||||
|
auth_require_user($pdo);
|
||||||
|
|
||||||
|
$documentRoot = rtrim(env_value('HERMES_DOCUMENT_ROOT', $env), DIRECTORY_SEPARATOR);
|
||||||
|
if ($documentRoot === '' || !str_starts_with($documentRoot, DIRECTORY_SEPARATOR)) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo 'Dokumentablage ist nicht konfiguriert.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolvedRoot = realpath($documentRoot);
|
||||||
|
$relativePath = (string) ($_GET['path'] ?? '');
|
||||||
|
|
||||||
|
if ($resolvedRoot === false || !is_dir($resolvedRoot) || $relativePath === '' || str_contains($relativePath, "\0") || str_contains($relativePath, '\\') || str_starts_with($relativePath, '/')) {
|
||||||
|
http_response_code(404);
|
||||||
|
echo 'Dokument nicht gefunden.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$segments = explode('/', $relativePath);
|
||||||
|
foreach ($segments as $segment) {
|
||||||
|
if ($segment === '' || $segment === '.' || $segment === '..') {
|
||||||
|
http_response_code(404);
|
||||||
|
echo 'Dokument nicht gefunden.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolvedFile = realpath($resolvedRoot . DIRECTORY_SEPARATOR . $relativePath);
|
||||||
|
$rootPrefix = $resolvedRoot . DIRECTORY_SEPARATOR;
|
||||||
|
if ($resolvedFile === false || !is_file($resolvedFile) || !is_readable($resolvedFile) || !str_starts_with($resolvedFile, $rootPrefix)) {
|
||||||
|
http_response_code(404);
|
||||||
|
echo 'Dokument nicht gefunden.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileSize = filesize($resolvedFile);
|
||||||
|
$mimeType = mime_content_type($resolvedFile);
|
||||||
|
if ($fileSize === false || $mimeType === false) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo 'Dokument konnte nicht bereitgestellt werden.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$downloadName = basename($resolvedFile);
|
||||||
|
header('Content-Type: ' . $mimeType);
|
||||||
|
header('Content-Length: ' . (string) $fileSize);
|
||||||
|
header("Content-Disposition: attachment; filename*=UTF-8''" . rawurlencode($downloadName));
|
||||||
|
header('Cache-Control: private, no-store');
|
||||||
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
readfile($resolvedFile);
|
||||||
Reference in new issue
Block a user