Upload via GUI (27 Dateien)
This commit is contained in:
@@ -37,6 +37,8 @@ Setzt den Katalog dieser Webseite als **offiziellen Katalog** eurer DeskHub-Vers
|
||||
|
||||
**Plugin:** ZIP mit `plugin.json` (`slug`, `name`, `version`, optional `description`, `author`, `requires`, `permissions`), siehe die DeskHub-Anleitung. Alle Angaben liest die Webseite aus der `plugin.json`.
|
||||
|
||||
**Sprachpaket (Mehrsprachigkeit):** ein normales Plugin ohne Berechtigungen, dessen `plugin.json` zusätzlich `"language": {"code": "en", "name": "English", "flag": "flag.svg", "strings": "strings.json"}` enthält. Die Webseite prüft den Sprachcode (`en`, `pt-br` …), merkt sich Code und Name und nennt sie im Katalog (`language`); DeskHub zeigt dann „🌐 Sprache: English“ und blendet nach der Aktivierung die Flagge zum Umschalten ein. Flagge und Texte liegen im Paket. Fertige Pakete: `Plugins/plugins/lang-en-1.0.0.zip` und `lang-de-1.0.0.zip`, passende Vorschaubilder in `theme/vorschaubilder/plugin-lang-en.png` und `plugin-lang-de.png`. Nach einem Update dieser Webseite legt sie die neue Spalte beim ersten Aufruf selbst an.
|
||||
|
||||
**Theme:** ZIP mit `theme.css` im Stammverzeichnis (nur CSS, Bilder und Schriften, kein PHP). Kennung, Name und Beschreibung tragt ihr beim Hochladen ein. Autor und Version stehen am besten im CSS-Kopf:
|
||||
|
||||
```css
|
||||
|
||||
@@ -82,6 +82,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
} else {
|
||||
$error = 'Ungültige Installation.';
|
||||
}
|
||||
} elseif ($action === 'feature' || $action === 'unfeature') {
|
||||
$message = site_set_featured((int) ($_POST['id'] ?? 0), $action === 'feature') ? ($action === 'feature' ? 'Als „Empfohlen“ markiert. DeskHub zeigt es nach der nächsten Katalog-Aktualisierung (spätestens in wenigen Minuten).' : 'Empfehlung entfernt.') : null;
|
||||
$error = $message ? null : 'Eintrag nicht gefunden.';
|
||||
} elseif ($action === 'delete') {
|
||||
$message = site_delete_version((int) ($_POST['id'] ?? 0)) ? 'Version entfernt.' : null;
|
||||
$error = $message ? null : 'Version nicht gefunden.';
|
||||
@@ -148,7 +151,8 @@ site_header('Verwaltung');
|
||||
<?php if (!$items): ?><p class="muted">Noch keine.</p><?php endif; ?>
|
||||
<?php foreach ($items as $it): ?>
|
||||
<table class="admin">
|
||||
<caption><?= site_h($it['name']) ?> <span class="muted small"><?= site_h($it['slug']) ?></span></caption>
|
||||
<caption><?= site_h($it['name']) ?> <span class="muted small"><?= site_h($it['slug']) ?></span> <?= !empty($it['featured']) ? '<span class="ok">★ Empfohlen</span>' : '' ?> <?php if (!empty($it['language']) && is_array($__l = json_decode((string) $it['language'], true))): ?><span class="muted small">🌐 Sprachpaket: <?= site_h((string) $__l['name']) ?> (<?= site_h((string) $__l['code']) ?>)</span><?php endif; ?>
|
||||
<form method="post" style="display:inline"><input type="hidden" name="action" value="<?= !empty($it['featured']) ? 'unfeature' : 'feature' ?>"><input type="hidden" name="csrf" value="<?= site_h(admin_csrf()) ?>"><input type="hidden" name="id" value="<?= (int) $it['id'] ?>"><button type="submit" class="link"><?= !empty($it['featured']) ? 'Empfehlung entfernen' : 'Als Empfehlung markieren' ?></button></form></caption>
|
||||
<?php foreach (site_versions((int) $it['id']) as $v): ?>
|
||||
<tr><td><?= site_h($v['version']) ?></td><td><?= site_h(substr($v['created_at'], 0, 16)) ?></td><td><?= (int) $v['downloads'] ?> Downloads</td>
|
||||
<td><?= $v['signature'] !== '' ? '<span class="ok">signiert</span>' : '<span class="warn">nicht signiert</span>' ?></td>
|
||||
|
||||
@@ -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'];
|
||||
|
||||
Reference in New Issue
Block a user