Community-Paket: Playtester-Programm, Starboard, Screenshot-Galerie
- Playtester: /playtester-setup postet Bewerbungs-Embed mit 🧪-Button; Toggle vergibt Rolle + DB-Eintrag; Liste + Rollen-Auswahl auf der Setup-Seite - Starboard: ab konfigurierbarem ⭐-Schwellwert Repost als Embed in den Best-of-Kanal (Dedupe, kein Selbst-Boarding); neue Intents/Partials für Reaktionen - Galerie: Bilder aus dem Screenshot-Kanal lokal archiviert (live + /galerie-backfill, Delete-Sync, Bot reagiert mit ⭐) → öffentliche /galerie-Seite mit Hover-Grid - Setup-Seite: Sektion // Community (Rolle, Starboard-Kanal + Schwellwert, Screenshot-Kanal) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+40
-8
@@ -3,6 +3,7 @@ import { EmbedBuilder } from 'discord.js';
|
||||
import {
|
||||
listDevlogs, searchDevlogs, listCommits, listReleases, archiveStats,
|
||||
getSetting, setSetting, createApiKey, listApiKeys, deleteApiKey,
|
||||
listGallery, listPlaytesters,
|
||||
} from '../db.js';
|
||||
import { config } from '../config.js';
|
||||
import { removeDevlog } from '../bot/devlog-archive.js';
|
||||
@@ -53,6 +54,23 @@ export function registerApiRoutes(app, client) {
|
||||
return { items, total, page, pageSize: PAGE_SIZE };
|
||||
});
|
||||
|
||||
// Screenshot-Galerie — öffentlich
|
||||
app.get('/api/gallery', async (request) => {
|
||||
const { limit, offset, page } = paging(request);
|
||||
const { items, total } = listGallery(limit, offset);
|
||||
const mapped = items.map(({ images, ...rest }) => ({
|
||||
...rest,
|
||||
images: JSON.parse(images || '[]').map((f) => `/gallery-assets/${f}`),
|
||||
}));
|
||||
return { items: mapped, total, page, pageSize: PAGE_SIZE };
|
||||
});
|
||||
|
||||
// Playtester-Liste — Admin
|
||||
app.get('/api/playtesters', async (request, reply) => {
|
||||
if (requireAdmin(request, reply)) return;
|
||||
return { playtesters: listPlaytesters() };
|
||||
});
|
||||
|
||||
// Roadmap — öffentlich, aus Gitea-Milestones (5-Minuten-Cache gegen API-Hammering)
|
||||
let roadmapCache = { at: 0, repo: null, data: null };
|
||||
app.get('/api/roadmap', async (request, reply) => {
|
||||
@@ -181,6 +199,10 @@ ${rssItems}
|
||||
gitea_url: getSetting('gitea_url') ?? config.giteaUrl,
|
||||
backup_enabled: getSetting('backup_enabled') !== '0',
|
||||
backup_channel_id: getSetting('backup_channel_id') ?? '',
|
||||
playtester_role_id: getSetting('playtester_role_id') ?? '',
|
||||
starboard_channel_id: getSetting('starboard_channel_id') ?? '',
|
||||
starboard_threshold: Number(getSetting('starboard_threshold')) || 3,
|
||||
screenshot_channel_id: getSetting('screenshot_channel_id') ?? '',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -208,11 +230,12 @@ ${rssItems}
|
||||
|
||||
const body = request.body ?? {};
|
||||
|
||||
// Kanäle: müssen existierende Textkanäle sein (release/backup dürfen leer sein = aus)
|
||||
for (const key of ['commit_channel_id', 'devlog_channel_id', 'release_channel_id', 'backup_channel_id']) {
|
||||
// Kanäle: müssen existierende Textkanäle sein (optionale dürfen leer sein = aus)
|
||||
const OPTIONAL_CHANNELS = ['release_channel_id', 'backup_channel_id', 'starboard_channel_id', 'screenshot_channel_id'];
|
||||
for (const key of ['commit_channel_id', 'devlog_channel_id', ...OPTIONAL_CHANNELS]) {
|
||||
if (body[key] === undefined) continue;
|
||||
const value = String(body[key]);
|
||||
if (value === '' && ['release_channel_id', 'backup_channel_id'].includes(key)) {
|
||||
if (value === '' && OPTIONAL_CHANNELS.includes(key)) {
|
||||
setSetting(key, '');
|
||||
continue;
|
||||
}
|
||||
@@ -222,18 +245,27 @@ ${rssItems}
|
||||
}
|
||||
setSetting(key, value);
|
||||
}
|
||||
// Ping-Rolle: muss existieren ('' = kein Ping)
|
||||
if (body.devlog_ping_role_id !== undefined) {
|
||||
const value = String(body.devlog_ping_role_id);
|
||||
// Rollen: müssen existieren ('' = Feature aus)
|
||||
for (const key of ['devlog_ping_role_id', 'playtester_role_id']) {
|
||||
if (body[key] === undefined) continue;
|
||||
const value = String(body[key]);
|
||||
if (value !== '') {
|
||||
const exists = [...client.guilds.cache.values()].some((g) =>
|
||||
g.roles?.cache?.has?.(value)
|
||||
);
|
||||
if (!exists) {
|
||||
return reply.code(400).send({ error: 'devlog_ping_role_id: Rolle nicht gefunden' });
|
||||
return reply.code(400).send({ error: `${key}: Rolle nicht gefunden` });
|
||||
}
|
||||
}
|
||||
setSetting('devlog_ping_role_id', value);
|
||||
setSetting(key, value);
|
||||
}
|
||||
// Starboard-Schwellwert: 1–50
|
||||
if (body.starboard_threshold !== undefined) {
|
||||
const n = Number(body.starboard_threshold);
|
||||
if (!Number.isInteger(n) || n < 1 || n > 50) {
|
||||
return reply.code(400).send({ error: 'starboard_threshold: 1–50' });
|
||||
}
|
||||
setSetting('starboard_threshold', String(n));
|
||||
}
|
||||
if (body.commit_feed_enabled !== undefined) {
|
||||
setSetting('commit_feed_enabled', body.commit_feed_enabled ? '1' : '0');
|
||||
|
||||
Reference in New Issue
Block a user