Add CMS features with admin interface and OAuth authentication integration

- Introduced Caddy server for serving frontend and API backend.
- Implemented admin dashboard for creating, editing, and managing events.
- Replaced session-based authentication with token-based OAuth using Gitea.
- Added support for drag-and-drop event reordering in the admin interface.
- Standardized Fastify route validation with JSON schemas.
- Enhanced authentication flow with cookie-based state and secure token storage.
- Reworked backend routes to handle publishing, event management, and content updates.
- Updated `Dockerfile.caddy` and `fly.toml` for deployment configuration.
This commit is contained in:
2025-12-08 16:00:40 +01:00
parent 3b6cb0a3fb
commit daccc43677
16 changed files with 603 additions and 186 deletions

View File

@ -4,9 +4,14 @@ import { db } from '../config/database.js';
import { contentSections } from '../db/schema.js';
import { eq } from 'drizzle-orm';
const contentSectionSchema = z.object({
contentJson: z.record(z.any()),
});
// Fastify JSON schema for content section body
const contentBodyJsonSchema = {
type: 'object',
required: ['contentJson'],
properties: {
contentJson: {}, // allow any JSON
},
} as const;
const contentRoute: FastifyPluginAsync = async (fastify) => {
@ -36,12 +41,12 @@ const contentRoute: FastifyPluginAsync = async (fastify) => {
// Update content section
fastify.put('/content/:section', {
schema: {
body: contentSectionSchema,
body: contentBodyJsonSchema,
},
preHandler: [fastify.authenticate],
}, async (request, reply) => {
const { section } = request.params as { section: string };
const { contentJson } = request.body as z.infer<typeof contentSectionSchema>;
const { contentJson } = request.body as any;
// Check if section exists
const [existing] = await db
@ -87,7 +92,7 @@ const contentRoute: FastifyPluginAsync = async (fastify) => {
const sections = await db.select().from(contentSections);
return {
sections: sections.map(s => ({
sections: (sections as any[]).map((s: any) => ({
section: s.sectionName,
content: s.contentJson,
updatedAt: s.updatedAt,