woodpecker soll nun auch das backend deployen
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

This commit is contained in:
2025-12-09 13:58:39 +01:00
parent e9a95ccf8d
commit c55e274718
6 changed files with 198 additions and 6 deletions

View File

@ -3,6 +3,9 @@ import { z } from 'zod';
import { db } from '../config/database.js';
import { galleryImages } from '../db/schema.js';
import { eq } from 'drizzle-orm';
import fs from 'fs';
import path from 'path';
import sharp from 'sharp';
// Fastify JSON schema for gallery image body
const galleryBodyJsonSchema = {
@ -54,6 +57,82 @@ const galleryRoute: FastifyPluginAsync = async (fastify) => {
return reply.code(201).send({ image: newImage });
});
// Upload image file (multipart)
fastify.post('/gallery/upload', {
preHandler: [fastify.authenticate],
}, async (request, reply) => {
try {
// Expect a single file field named "file"
const file = await (request as any).file();
if (!file) {
return reply.code(400).send({ error: 'No file uploaded' });
}
const altText = (file.fields?.altText?.value as string | undefined) || '';
const displayOrderRaw = (file.fields?.displayOrder?.value as string | undefined) || '0';
const displayOrder = Number.parseInt(displayOrderRaw) || 0;
const mime = file.mimetype as string | undefined;
if (!mime || !mime.startsWith('image/')) {
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');
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });
// Read uploaded stream into buffer
const chunks: Buffer[] = [];
for await (const chunk of file.file) {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
}
const inputBuffer = Buffer.concat(chunks);
// Generate filename
const stamp = Date.now().toString(36);
const rand = Math.random().toString(36).slice(2, 8);
const baseName = `${stamp}-${rand}`;
// Try to convert to webp and limit size; fallback to original
let outBuffer: Buffer | null = null;
let outExt = '.webp';
try {
outBuffer = await sharp(inputBuffer)
.rotate()
.resize({ width: 1600, withoutEnlargement: true })
.webp({ quality: 82 })
.toBuffer();
} catch {
outBuffer = inputBuffer;
// naive extension from mimetype
const extFromMime = mime.split('/')[1] || 'bin';
outExt = '.' + extFromMime.replace(/[^a-z0-9]/gi, '').toLowerCase();
}
const filename = baseName + outExt;
const destPath = path.join(uploadDir, filename);
fs.writeFileSync(destPath, outBuffer);
// Public URL (served via /static)
const publicUrl = `/static/images/gallery/${filename}`;
// Store in DB (optional but useful)
const [row] = await db.insert(galleryImages).values({
imageUrl: publicUrl,
altText: altText || filename,
displayOrder,
isPublished: true,
}).returning();
return reply.code(201).send({ image: row });
} catch (err) {
fastify.log.error({ err }, 'Upload failed');
return reply.code(500).send({ error: 'Failed to upload image' });
}
});
// Update gallery image
fastify.put('/gallery/:id', {
schema: {