From af4877300f12fb0221251cb7d0b156b30ad5285f Mon Sep 17 00:00:00 2001 From: Kenzo Date: Tue, 9 Dec 2025 15:53:39 +0100 Subject: [PATCH] Add public endpoints and refactor deployments - Implemented public `/gallery/public` and `/events/public` endpoints for fetching published data without authentication. - Updated persistent volume configuration for Fly.io across backend and static file serving. - Adjusted frontend to dynamically fetch events and gallery images from backend API. - Refined Woodpecker pipeline for clearer separation of backend and frontend deployments. --- .woodpecker.yml | 14 +++++------ backend/src/index.ts | 6 +++-- backend/src/routes/events.ts | 10 +++++++- backend/src/routes/gallery.ts | 16 +++++++++---- src/pages/index.astro | 45 +++++++++++++++++++++++++---------- 5 files changed, 64 insertions(+), 27 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index eab0270..e83ff9d 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,3 +1,9 @@ +when: + branch: + - main + event: + - push + steps: deploy_frontend: image: node:20 @@ -9,7 +15,7 @@ steps: - export PATH="$HOME/.fly/bin:$PATH" - flyctl deploy --config fly.toml --app gallus-pub --remote-only - build_and_deploy_backend: + deploy_backend: image: node:20 environment: FLY_API_TOKEN: @@ -19,9 +25,3 @@ steps: - curl -L https://fly.io/install.sh | sh - export PATH="$HOME/.fly/bin:$PATH" - flyctl deploy --config fly.toml --app gallus-cms-backend --remote-only - -when: - branch: - - main - event: - - push diff --git a/backend/src/index.ts b/backend/src/index.ts index ac320a6..403cf73 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -60,10 +60,12 @@ fastify.register(multipart, { }, }); -// Serve static files (uploaded images, etc.) +// Serve static files (uploaded images, etc.) from persistent volume +const dataDir = env.GIT_WORKSPACE_DIR || path.join(process.cwd(), 'data'); fastify.register(fastifyStatic, { - root: path.join(process.cwd(), 'public'), + root: dataDir, prefix: '/static/', + decorateReply: false }); // Decorate fastify with authenticate method diff --git a/backend/src/routes/events.ts b/backend/src/routes/events.ts index b38c370..8e1553e 100644 --- a/backend/src/routes/events.ts +++ b/backend/src/routes/events.ts @@ -36,7 +36,15 @@ const reorderBodyJsonSchema = { } as const; const eventsRoute: FastifyPluginAsync = async (fastify) => { - // List all events (by displayOrder) + // PUBLIC: List published events (no auth required) + fastify.get('/events/public', async () => { + const all = await db.select().from(events) + .where(eq(events.isPublished, true)) + .orderBy(events.displayOrder); + return { events: all }; + }); + + // List all events (by displayOrder) - admin only fastify.get('/events', { preHandler: [fastify.authenticate] }, async () => { const all = await db.select().from(events).orderBy(events.displayOrder); return { events: all }; diff --git a/backend/src/routes/gallery.ts b/backend/src/routes/gallery.ts index 434c9f3..966ea3d 100644 --- a/backend/src/routes/gallery.ts +++ b/backend/src/routes/gallery.ts @@ -21,7 +21,15 @@ const galleryBodyJsonSchema = { const galleryRoute: FastifyPluginAsync = async (fastify) => { - // List all gallery images + // PUBLIC: List published gallery images (no auth required) + fastify.get('/gallery/public', async () => { + const images = await db.select().from(galleryImages) + .where(eq(galleryImages.isPublished, true)) + .orderBy(galleryImages.displayOrder); + return { images }; + }); + + // List all gallery images - admin only fastify.get('/gallery', { preHandler: [fastify.authenticate], }, async (request, reply) => { @@ -77,9 +85,9 @@ const galleryRoute: FastifyPluginAsync = async (fastify) => { return reply.code(400).send({ error: 'Only image uploads are allowed' }); } - // Prepare directories - const publicRoot = path.join(process.cwd(), 'public'); - const uploadDir = path.join(publicRoot, 'images', 'gallery'); + // Prepare directories - use persistent volume for Fly.io + const dataDir = process.env.GIT_WORKSPACE_DIR || path.join(process.cwd(), 'data'); + const uploadDir = path.join(dataDir, 'images', 'gallery'); if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true }); // Read uploaded stream into buffer diff --git a/src/pages/index.astro b/src/pages/index.astro index 34a324b..abe7868 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -8,20 +8,39 @@ import ImageCarousel from "../components/ImageCarousel.astro"; import Contact from "../components/Contact.astro"; import About from "../components/About.astro"; -const events = [ - { - image: "/static/images/gallery/miyma9zc-8he1di.webp", - title: "Test", - date: "2025-12-10", - description: ` - Das ist ein test event - `, - } -]; +const API_BASE = 'https://cms.gallus-pub.ch'; -const images = [ - { src: "/static/images/gallery/miyma9zc-8he1di.webp", alt: "Schwarzes bild" } -]; +// Fetch events from backend API +let events = []; +try { + const eventsResponse = await fetch(`${API_BASE}/api/events/public`); + if (eventsResponse.ok) { + const eventsData = await eventsResponse.json(); + events = (eventsData.events || []).map((ev: any) => ({ + image: `${API_BASE}${ev.imageUrl}`, + title: ev.title, + date: ev.date, + description: ev.description + })); + } +} catch (error) { + console.error('Failed to fetch events:', error); +} + +// Fetch gallery images from backend API +let images = []; +try { + const galleryResponse = await fetch(`${API_BASE}/api/gallery/public`); + if (galleryResponse.ok) { + const galleryData = await galleryResponse.json(); + images = (galleryData.images || []).map((img: any) => ({ + src: `${API_BASE}${img.imageUrl}`, + alt: img.altText + })); + } +} catch (error) { + console.error('Failed to fetch gallery:', error); +} ---