Öffentliche Roadmap-Seite aus Gitea-Milestones
- GET /api/roadmap (public): Milestones des Setting roadmap_repo, 5-min-Cache, letzter guter Stand als Fallback bei Gitea-Ausfall - /roadmap: Gruppen In Arbeit / Geplant / Fertig, Fortschrittsbalken im Brand-Look, Ziel-Monat, Markdown-Beschreibungen; Nav-Link öffentlich - Setup-Seite: Roadmap-Repo konfigurierbar Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+34
-2
@@ -6,7 +6,8 @@ import {
|
||||
} from '../db.js';
|
||||
import { config } from '../config.js';
|
||||
import { removeDevlog } from '../bot/devlog-archive.js';
|
||||
import { commitChannelId, devlogChannelId, releaseChannelId, devlogPingRoleId, publicUrl } from '../runtime-settings.js';
|
||||
import { commitChannelId, devlogChannelId, releaseChannelId, devlogPingRoleId, publicUrl, roadmapRepo } from '../runtime-settings.js';
|
||||
import { getMilestones } from '../gitea-api.js';
|
||||
import { getSessionUser, isAdmin } from './auth.js';
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
@@ -52,6 +53,36 @@ export function registerApiRoutes(app, client) {
|
||||
return { items, total, page, pageSize: PAGE_SIZE };
|
||||
});
|
||||
|
||||
// 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) => {
|
||||
const repo = roadmapRepo();
|
||||
if (roadmapCache.data && roadmapCache.repo === repo && Date.now() - roadmapCache.at < 5 * 60_000) {
|
||||
return roadmapCache.data;
|
||||
}
|
||||
try {
|
||||
const milestones = await getMilestones(repo);
|
||||
const data = {
|
||||
repo,
|
||||
milestones: milestones.map((m) => ({
|
||||
title: m.title,
|
||||
description: m.description ?? '',
|
||||
state: m.state, // 'open' | 'closed'
|
||||
open: m.open_issues ?? 0,
|
||||
closed: m.closed_issues ?? 0,
|
||||
due_on: m.due_on ?? null,
|
||||
})),
|
||||
};
|
||||
roadmapCache = { at: Date.now(), repo, data };
|
||||
return data;
|
||||
} catch (error) {
|
||||
request.log.error({ err: error }, 'Roadmap-Abruf fehlgeschlagen');
|
||||
// Letzten guten Stand weiterreichen, falls vorhanden
|
||||
if (roadmapCache.data && roadmapCache.repo === repo) return roadmapCache.data;
|
||||
return reply.code(502).send({ error: 'Roadmap nicht abrufbar' });
|
||||
}
|
||||
});
|
||||
|
||||
// RSS-Feed der Devlogs — öffentlich abonnierbar
|
||||
app.get('/feed.xml', async (request, reply) => {
|
||||
const { items } = listDevlogs(20, 0);
|
||||
@@ -144,6 +175,7 @@ ${rssItems}
|
||||
weekly_recap_enabled: getSetting('weekly_recap_enabled') !== '0',
|
||||
devlog_threads_enabled: getSetting('devlog_threads_enabled') !== '0',
|
||||
bug_report_repo: getSetting('bug_report_repo') ?? 'D4rkst3r/EcoGame',
|
||||
roadmap_repo: getSetting('roadmap_repo') ?? 'D4rkst3r/EcoGame',
|
||||
watchdog_urls: getSetting('watchdog_urls') ?? '',
|
||||
public_url: publicUrl(),
|
||||
gitea_url: getSetting('gitea_url') ?? config.giteaUrl,
|
||||
@@ -215,7 +247,7 @@ ${rssItems}
|
||||
if (body.backup_enabled !== undefined) {
|
||||
setSetting('backup_enabled', body.backup_enabled ? '1' : '0');
|
||||
}
|
||||
for (const key of ['commit_branch_filter', 'ignored_repos', 'bug_report_repo', 'watchdog_urls']) {
|
||||
for (const key of ['commit_branch_filter', 'ignored_repos', 'bug_report_repo', 'watchdog_urls', 'roadmap_repo']) {
|
||||
if (body[key] !== undefined) {
|
||||
setSetting(key, String(body[key]).trim());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user