Add public endpoints and refactor deployments
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

- 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.
This commit is contained in:
2025-12-09 15:53:39 +01:00
parent 4a103cf7d6
commit af4877300f
5 changed files with 64 additions and 27 deletions

View File

@ -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

View File

@ -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

View File

@ -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 };

View File

@ -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

View File

@ -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);
}
---
<Layout>