import type { HttpContext } from '@adonisjs/core/http' import vpsConfig from '#config/vps' import CaddyfileVersion from '#models/caddyfile_version' import UserError from '#exceptions/user_error' import caddyService, { parseCaddyfile, type ReloadResult } from '#services/caddy_service' import siteMonitor from '#services/site_monitor' import { actor, audit } from '#services/audit' import { updateCaddyfileValidator } from '#validators/caddy' export default class CaddyController { async show() { const content = await caddyService.read() return { path: vpsConfig.caddy.caddyfilePath, container: vpsConfig.caddy.container, content, sites: parseCaddyfile(content), } } async update(ctx: HttpContext) { const { content, reason } = await ctx.request.validateUsing(updateCaddyfileValidator) const result = await caddyService.saveAndReload(content, { username: actor(ctx).username, reason: reason || 'Modification manuelle', }) return this.#respond(ctx, 'Modification du Caddyfile', result) } async reload(ctx: HttpContext) { const result = await caddyService.reload() return this.#respond(ctx, 'Rechargement de Caddy', result) } async versions() { const versions = await CaddyfileVersion.query() .select('id', 'username', 'reason', 'created_at') .orderBy('id', 'desc') return versions.map((version) => ({ id: version.id, username: version.username, reason: version.reason, createdAt: version.createdAt.toISO(), })) } async version({ params }: HttpContext) { const version = await CaddyfileVersion.find(params.id) if (!version) throw new UserError('Version introuvable.', 404) return { id: version.id, username: version.username, reason: version.reason, createdAt: version.createdAt.toISO(), content: version.content, } } async restore(ctx: HttpContext) { const version = await CaddyfileVersion.find(ctx.params.id) if (!version) throw new UserError('Version introuvable.', 404) const result = await caddyService.saveAndReload(version.content, { username: actor(ctx).username, reason: `Restauration de la version #${version.id}`, }) return this.#respond(ctx, `Restauration du Caddyfile (#${version.id})`, result) } async #respond(ctx: HttpContext, action: string, result: ReloadResult) { await audit(ctx, { action, target: vpsConfig.caddy.caddyfilePath, status: result.ok ? 'success' : 'error', output: result.output, }) if (!result.ok) { return ctx.response.unprocessableEntity({ message: 'Caddy a refusé la configuration : le Caddyfile est inchangé.', output: result.output, }) } /** * New or removed domains show up right away on the sites page. */ siteMonitor.sync().catch(() => {}) return { ok: true, output: result.output } } }