Upload via GUI (27 Dateien)

This commit is contained in:
2026-10-24 20:17:11 +00:00
parent ad961bc601
commit e457b97dce
3 changed files with 37 additions and 8 deletions
+30 -7
View File
@@ -20,6 +20,7 @@ function site_known_permissions(): array
'ui.menu' => 'Eigene Menüpunkte und Seiten im Mitarbeiterbereich',
'ui.sidebar' => 'Bausteine in der Seitenleiste der Ticketansicht',
'api.endpoints' => 'Eigene Endpunkte in der Mitarbeiter-API',
'api.public' => 'Öffentliche Webhook-Adresse (zum Beispiel für Discord oder Telegram); das Plugin prüft die Echtheit der Anfragen selbst',
'db.migrations' => 'Eigene Datenbank-Tabellen anlegen',
];
}
@@ -94,9 +95,21 @@ function site_db(): PDO
signature TEXT NOT NULL DEFAULT '', size INTEGER NOT NULL, requires TEXT NOT NULL DEFAULT '', permissions TEXT NOT NULL DEFAULT '',
downloads INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, UNIQUE (item_id, version),
FOREIGN KEY (item_id) REFERENCES items(id) ON DELETE CASCADE)");
// Empfehlung (nachträglich ergänzt, damit bestehende Datenbanken ohne Handarbeit weiterlaufen)
$cols = array_column($pdo->query('PRAGMA table_info(items)')->fetchAll(), 'name');
if (!in_array('featured', $cols, true)) $pdo->exec('ALTER TABLE items ADD COLUMN featured INTEGER NOT NULL DEFAULT 0');
if (!in_array('language', $cols, true)) $pdo->exec('ALTER TABLE items ADD COLUMN language TEXT NULL');
return $pdo;
}
/** Plugin bzw. Theme als „Empfohlen“ markieren oder die Markierung entfernen. */
function site_set_featured(int $itemId, bool $featured): bool
{
$stmt = site_db()->prepare('UPDATE items SET featured = ? WHERE id = ?');
$stmt->execute([$featured ? 1 : 0, $itemId]);
return $stmt->rowCount() > 0;
}
function site_h(?string $s): string
{
return htmlspecialchars((string) $s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
@@ -181,10 +194,18 @@ function site_inspect_package(string $type, string $zipPath): array
if ($name === '') return ['ok' => false, 'error' => 'plugin.json: "name" fehlt.'];
if (!site_valid_version($version)) return ['ok' => false, 'error' => 'plugin.json: ungültige Versionsnummer.'];
$perms = array_values(array_unique(array_map('strval', (array) ($data['permissions'] ?? []))));
foreach ($perms as $p) if (!isset(site_known_permissions()[$p])) return ['ok' => false, 'error' => "plugin.json: unbekannte Berechtigung \"{$p}\"."];
// Neue Berechtigungen, die DeskHub später einführt, dürfen die Webseite nicht blockieren: Form "bereich.name" genügt, den Inhalt prüft DeskHub beim Installieren
foreach ($perms as $p) if (!isset(site_known_permissions()[$p]) && !preg_match('/^[a-z]{2,12}\.[a-z_]{2,30}$/', $p)) return ['ok' => false, 'error' => "plugin.json: unbekannte Berechtigung \"{$p}\"."];
// Sprachpaket: "language": {"code":"en","name":"English"} (die Flagge und die Texte liegen im Paket, DeskHub liest sie dort)
$lang = null;
if (is_array($data['language'] ?? null)) {
$code = strtolower((string) ($data['language']['code'] ?? ''));
if (!preg_match('/^[a-z]{2,3}(-[a-z]{2,4})?$/', $code)) return ['ok' => false, 'error' => 'plugin.json: language.code fehlt oder ist ungültig (zum Beispiel en oder pt-br).'];
$lang = ['code' => $code, 'name' => mb_substr(trim((string) ($data['language']['name'] ?? $code)), 0, 40) ?: $code];
}
sort($perms);
return ['ok' => true, 'meta' => ['slug' => $slug, 'name' => mb_substr($name, 0, 120), 'version' => $version, 'description' => mb_substr((string) ($data['description'] ?? ''), 0, 1000),
'author' => mb_substr((string) ($data['author'] ?? ''), 0, 120), 'requires' => (string) ($data['requires'] ?? ''), 'permissions' => $perms]];
'author' => mb_substr((string) ($data['author'] ?? ''), 0, 120), 'requires' => (string) ($data['requires'] ?? ''), 'permissions' => $perms, 'language' => $lang]];
}
// Theme: Angaben stehen im Kopf der theme.css (Author:, Version:)
$head = substr($main, 0, 2000);
@@ -278,12 +299,12 @@ function site_publish(string $type, string $zipPath, array $form = [], ?string $
$pdo->beginTransaction();
try {
if ($item) {
$pdo->prepare('UPDATE items SET name = ?, description = ?, author = ?, preview = COALESCE(?, preview), updated_at = ? WHERE id = ?')
->execute([$meta['name'], $meta['description'], $meta['author'], $preview, $now, $item['id']]);
$pdo->prepare('UPDATE items SET name = ?, description = ?, author = ?, preview = COALESCE(?, preview), language = ?, updated_at = ? WHERE id = ?')
->execute([$meta['name'], $meta['description'], $meta['author'], $preview, !empty($meta['language']) ? json_encode($meta['language'], JSON_UNESCAPED_UNICODE) : null, $now, $item['id']]);
$itemId = (int) $item['id'];
} else {
$pdo->prepare('INSERT INTO items (type, slug, name, description, author, preview, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)')
->execute([$type, $meta['slug'], $meta['name'], $meta['description'], $meta['author'], $preview, $now, $now]);
$pdo->prepare('INSERT INTO items (type, slug, name, description, author, preview, language, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)')
->execute([$type, $meta['slug'], $meta['name'], $meta['description'], $meta['author'], $preview, !empty($meta['language']) ? json_encode($meta['language'], JSON_UNESCAPED_UNICODE) : null, $now, $now]);
$itemId = (int) $pdo->lastInsertId();
}
$pdo->prepare('INSERT INTO versions (item_id, version, file, sha256, signature, size, requires, permissions, created_at) VALUES (?,?,?,?,?,?,?,?,?)')
@@ -334,7 +355,7 @@ function site_delete_version(int $versionId): bool
function site_items(string $type, string $search = ''): array
{
$pdo = site_db();
$stmt = $pdo->prepare('SELECT * FROM items WHERE type = ? ORDER BY name COLLATE NOCASE');
$stmt = $pdo->prepare('SELECT * FROM items WHERE type = ? ORDER BY featured DESC, name COLLATE NOCASE');
$stmt->execute([$type]);
$out = [];
foreach ($stmt->fetchAll() as $item) {
@@ -380,6 +401,8 @@ function site_catalog(string $type): array
'downloadUrl' => $base . '/download.php?type=' . $type . '&slug=' . rawurlencode($item['slug']) . '&version=' . rawurlencode($v['version']),
'sha256' => $v['sha256'], 'signature' => $v['signature'],
];
if (!empty($item['featured'])) $entry['featured'] = true;
if ($type === 'plugin' && !empty($item['language']) && is_array($l = json_decode((string) $item['language'], true))) $entry['language'] = ['code' => (string) $l['code'], 'name' => (string) $l['name']];
if ($item['preview']) $entry['previewUrl'] = $base . '/preview.php?file=' . rawurlencode($item['preview']);
if ($type === 'plugin') {
$entry['requires'] = $v['requires'];