Add public endpoints and refactor deployments
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
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:
@ -1,3 +1,9 @@
|
|||||||
|
when:
|
||||||
|
branch:
|
||||||
|
- main
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
deploy_frontend:
|
deploy_frontend:
|
||||||
image: node:20
|
image: node:20
|
||||||
@ -9,7 +15,7 @@ steps:
|
|||||||
- export PATH="$HOME/.fly/bin:$PATH"
|
- export PATH="$HOME/.fly/bin:$PATH"
|
||||||
- flyctl deploy --config fly.toml --app gallus-pub --remote-only
|
- flyctl deploy --config fly.toml --app gallus-pub --remote-only
|
||||||
|
|
||||||
build_and_deploy_backend:
|
deploy_backend:
|
||||||
image: node:20
|
image: node:20
|
||||||
environment:
|
environment:
|
||||||
FLY_API_TOKEN:
|
FLY_API_TOKEN:
|
||||||
@ -19,9 +25,3 @@ steps:
|
|||||||
- curl -L https://fly.io/install.sh | sh
|
- curl -L https://fly.io/install.sh | sh
|
||||||
- export PATH="$HOME/.fly/bin:$PATH"
|
- export PATH="$HOME/.fly/bin:$PATH"
|
||||||
- flyctl deploy --config fly.toml --app gallus-cms-backend --remote-only
|
- flyctl deploy --config fly.toml --app gallus-cms-backend --remote-only
|
||||||
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- main
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|||||||
@ -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, {
|
fastify.register(fastifyStatic, {
|
||||||
root: path.join(process.cwd(), 'public'),
|
root: dataDir,
|
||||||
prefix: '/static/',
|
prefix: '/static/',
|
||||||
|
decorateReply: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// Decorate fastify with authenticate method
|
// Decorate fastify with authenticate method
|
||||||
|
|||||||
@ -36,7 +36,15 @@ const reorderBodyJsonSchema = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const eventsRoute: FastifyPluginAsync = async (fastify) => {
|
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 () => {
|
fastify.get('/events', { preHandler: [fastify.authenticate] }, async () => {
|
||||||
const all = await db.select().from(events).orderBy(events.displayOrder);
|
const all = await db.select().from(events).orderBy(events.displayOrder);
|
||||||
return { events: all };
|
return { events: all };
|
||||||
|
|||||||
@ -21,7 +21,15 @@ const galleryBodyJsonSchema = {
|
|||||||
|
|
||||||
const galleryRoute: FastifyPluginAsync = async (fastify) => {
|
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', {
|
fastify.get('/gallery', {
|
||||||
preHandler: [fastify.authenticate],
|
preHandler: [fastify.authenticate],
|
||||||
}, async (request, reply) => {
|
}, async (request, reply) => {
|
||||||
@ -77,9 +85,9 @@ const galleryRoute: FastifyPluginAsync = async (fastify) => {
|
|||||||
return reply.code(400).send({ error: 'Only image uploads are allowed' });
|
return reply.code(400).send({ error: 'Only image uploads are allowed' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare directories
|
// Prepare directories - use persistent volume for Fly.io
|
||||||
const publicRoot = path.join(process.cwd(), 'public');
|
const dataDir = process.env.GIT_WORKSPACE_DIR || path.join(process.cwd(), 'data');
|
||||||
const uploadDir = path.join(publicRoot, 'images', 'gallery');
|
const uploadDir = path.join(dataDir, 'images', 'gallery');
|
||||||
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });
|
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });
|
||||||
|
|
||||||
// Read uploaded stream into buffer
|
// Read uploaded stream into buffer
|
||||||
|
|||||||
@ -8,20 +8,39 @@ import ImageCarousel from "../components/ImageCarousel.astro";
|
|||||||
import Contact from "../components/Contact.astro";
|
import Contact from "../components/Contact.astro";
|
||||||
import About from "../components/About.astro";
|
import About from "../components/About.astro";
|
||||||
|
|
||||||
const events = [
|
const API_BASE = 'https://cms.gallus-pub.ch';
|
||||||
{
|
|
||||||
image: "/static/images/gallery/miyma9zc-8he1di.webp",
|
|
||||||
title: "Test",
|
|
||||||
date: "2025-12-10",
|
|
||||||
description: `
|
|
||||||
Das ist ein test event
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const images = [
|
// Fetch events from backend API
|
||||||
{ src: "/static/images/gallery/miyma9zc-8he1di.webp", alt: "Schwarzes bild" }
|
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>
|
<Layout>
|
||||||
|
|||||||
Reference in New Issue
Block a user