Willkommens-Karten, Geburtstage, Devlog-Permalinks mit OG-Vorschau, Auto-Publish
- Willkommens-Karten: gerendertes PNG (SVG → sharp) mit Avatar im Neon-Ring, Willkommens-Schriftzug und Member-Nummer; Fallback aufs bisherige Embed wenn das Rendering scheitert; Dockerfile installiert fonts-dejavu-core für die Text-Darstellung - Geburtstags-System: /geburtstag setzen|entfernen (birthdays-Tabelle), tägliche Runde ab 09:00 Europe/Berlin (Doppel-Post-Schutz über last_birthday_run), Gratulations-Embed + Tages-Rolle (wird am nächsten Morgen wieder abgeräumt); Kanal + Rolle im Community-Tab - Devlog-Permalinks: /devlogs/:id als eigene Seite (GET /api/devlogs/:id), Link-Symbol an jeder Karte, Link-kopieren-Button; der Server injiziert Open-Graph-Tags ins SPA-HTML — Devlog-Links zeigen Titel, Anriss und Bild, alle anderen Seiten bekommen Default-Tags (auch die Startseite) - Auto-Publish: maybeCrosspost() veröffentlicht Devlog-, Release-, Composer- und geplante Posts automatisch in Ankündigungs-Kanälen - brandEmbed: leere Avatar-URL crasht nicht mehr die Footer-Validierung Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+19
-2
@@ -1,7 +1,7 @@
|
||||
// REST-API fürs Webinterface: Devlogs öffentlich, Commits + Settings nur für den Admin
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import {
|
||||
listDevlogs, searchDevlogs, listCommits, listReleases, archiveStats,
|
||||
listDevlogs, searchDevlogs, getDevlog, listCommits, listReleases, archiveStats,
|
||||
getSetting, setSetting, createApiKey, listApiKeys, deleteApiKey,
|
||||
listGallery, listPlaytesters, topWishes, commitHeatmap,
|
||||
createRoleMenu, updateRoleMenu, getRoleMenu, listRoleMenus, deleteRoleMenu,
|
||||
@@ -89,6 +89,18 @@ export function registerApiRoutes(app, client) {
|
||||
return { items: mapped, total, page, pageSize: PAGE_SIZE };
|
||||
});
|
||||
|
||||
// Einzelnes Devlog (Permalink-Seite /devlogs/:id)
|
||||
app.get('/api/devlogs/:id', async (request, reply) => {
|
||||
const item = getDevlog(String(request.params.id));
|
||||
if (!item) return reply.code(404).send({ error: 'Devlog nicht gefunden' });
|
||||
return {
|
||||
item: {
|
||||
...item,
|
||||
images: JSON.parse(item.images || '[]').map((f) => `/devlog-assets/${f}`),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// Changelog — öffentlich (Releases aller Repos)
|
||||
app.get('/api/releases', async (request) => {
|
||||
const { limit, offset, page } = paging(request);
|
||||
@@ -339,6 +351,8 @@ ${rssItems}
|
||||
server_alert_channel_id: getSetting('server_alert_channel_id') ?? '',
|
||||
member_gate_enabled: getSetting('member_gate_enabled') !== '0',
|
||||
discord_invite_url: getSetting('discord_invite_url') ?? '',
|
||||
birthday_channel_id: getSetting('birthday_channel_id') ?? '',
|
||||
birthday_role_id: getSetting('birthday_role_id') ?? '',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -385,6 +399,7 @@ ${rssItems}
|
||||
'screenshot_channel_id', 'modmail_channel_id', 'welcome_channel_id',
|
||||
'modlog_channel_id', 'status_channel_id', 'voting_channel_id', 'ticket_channel_id',
|
||||
'events_announce_channel_id', 'social_announce_channel_id', 'server_alert_channel_id',
|
||||
'birthday_channel_id',
|
||||
];
|
||||
for (const key of ['commit_channel_id', 'devlog_channel_id', ...OPTIONAL_CHANNELS]) {
|
||||
if (body[key] === undefined) continue;
|
||||
@@ -400,7 +415,7 @@ ${rssItems}
|
||||
setSetting(key, value);
|
||||
}
|
||||
// Rollen: müssen existieren ('' = Feature aus)
|
||||
for (const key of ['devlog_ping_role_id', 'playtester_role_id', 'autorole_id']) {
|
||||
for (const key of ['devlog_ping_role_id', 'playtester_role_id', 'autorole_id', 'birthday_role_id']) {
|
||||
if (body[key] === undefined) continue;
|
||||
const value = String(body[key]);
|
||||
if (value !== '') {
|
||||
@@ -1005,6 +1020,8 @@ ${rssItems}
|
||||
}
|
||||
|
||||
const message = await channel.send(payload);
|
||||
const { maybeCrosspost } = await import('../embeds.js');
|
||||
await maybeCrosspost(message);
|
||||
request.log.info(`Composer: Nachricht ${message.id} gesendet`);
|
||||
logAudit(getSessionUser(request), 'composer gesendet', `#${channel.name ?? channelId}`);
|
||||
return { ok: true, edited: false, message_id: message.id };
|
||||
|
||||
Reference in New Issue
Block a user