- 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.
122 lines
2.8 KiB
TypeScript
122 lines
2.8 KiB
TypeScript
import { FastifyPluginAsync } from 'fastify';
|
|
import { z } from 'zod';
|
|
import { db } from '../config/database.js';
|
|
import { siteSettings } from '../db/schema.js';
|
|
import { eq } from 'drizzle-orm';
|
|
|
|
// Fastify JSON schema for settings body
|
|
const settingBodyJsonSchema = {
|
|
type: 'object',
|
|
required: ['value'],
|
|
properties: {
|
|
value: { type: 'string' },
|
|
},
|
|
} as const;
|
|
|
|
const settingsRoute: FastifyPluginAsync = async (fastify) => {
|
|
|
|
// Get all settings
|
|
fastify.get('/settings', {
|
|
preHandler: [fastify.authenticate],
|
|
}, async (request, reply) => {
|
|
const settings = await db.select().from(siteSettings);
|
|
|
|
return {
|
|
settings: settings.reduce((acc, setting) => {
|
|
acc[setting.key] = setting.value;
|
|
return acc;
|
|
}, {} as Record<string, string>),
|
|
};
|
|
});
|
|
|
|
// Get single setting
|
|
fastify.get('/settings/:key', {
|
|
preHandler: [fastify.authenticate],
|
|
}, async (request, reply) => {
|
|
const { key } = request.params as { key: string };
|
|
|
|
const [setting] = await db
|
|
.select()
|
|
.from(siteSettings)
|
|
.where(eq(siteSettings.key, key))
|
|
.limit(1);
|
|
|
|
if (!setting) {
|
|
return reply.code(404).send({ error: 'Setting not found' });
|
|
}
|
|
|
|
return {
|
|
key: setting.key,
|
|
value: setting.value,
|
|
updatedAt: setting.updatedAt,
|
|
};
|
|
});
|
|
|
|
// Update setting
|
|
fastify.put('/settings/:key', {
|
|
schema: {
|
|
body: settingBodyJsonSchema,
|
|
},
|
|
preHandler: [fastify.authenticate],
|
|
}, async (request, reply) => {
|
|
const { key } = request.params as { key: string };
|
|
const { value } = request.body as any;
|
|
|
|
// Check if setting exists
|
|
const [existing] = await db
|
|
.select()
|
|
.from(siteSettings)
|
|
.where(eq(siteSettings.key, key))
|
|
.limit(1);
|
|
|
|
let result;
|
|
|
|
if (existing) {
|
|
// Update existing
|
|
[result] = await db
|
|
.update(siteSettings)
|
|
.set({
|
|
value,
|
|
updatedAt: new Date(),
|
|
})
|
|
.where(eq(siteSettings.key, key))
|
|
.returning();
|
|
} else {
|
|
// Create new
|
|
[result] = await db
|
|
.insert(siteSettings)
|
|
.values({
|
|
key,
|
|
value,
|
|
})
|
|
.returning();
|
|
}
|
|
|
|
return {
|
|
key: result.key,
|
|
value: result.value,
|
|
updatedAt: result.updatedAt,
|
|
};
|
|
});
|
|
|
|
// Delete setting
|
|
fastify.delete('/settings/:key', {
|
|
preHandler: [fastify.authenticate],
|
|
}, async (request, reply) => {
|
|
const { key } = request.params as { key: string };
|
|
|
|
const [deleted] = await db
|
|
.delete(siteSettings)
|
|
.where(eq(siteSettings.key, key))
|
|
.returning();
|
|
|
|
if (!deleted) {
|
|
return reply.code(404).send({ error: 'Setting not found' });
|
|
}
|
|
|
|
return { message: 'Setting deleted successfully' };
|
|
});
|
|
};
|
|
|
|
export default settingsRoute;
|