65 lines
2.5 KiB
TypeScript
65 lines
2.5 KiB
TypeScript
/**
|
||
* POST /api/media/upload – multipart upload; saves to local disk
|
||
* DELETE /api/media/:key – delete a file by key (admin/event_manager)
|
||
*
|
||
* Upload flow (replaces the old presigned-URL pattern):
|
||
* 1. Client POSTs multipart/form-data with fields: itemId, mediaType, plus the file
|
||
* 2. Server saves to UPLOAD_DIR/items/<itemId>/<uuid>.<ext>
|
||
* 3. Server returns { url, key, mimetype, sizeBytes }
|
||
* 4. Client calls POST /api/items/:id/media with { mediaType, url } to attach the
|
||
* record to the item (existing endpoint in routes/items.ts)
|
||
*
|
||
* Files are served as static assets at /media/* (see app.ts).
|
||
* Everything stays on the local machine — no internet required.
|
||
*/
|
||
import { Router } from "express";
|
||
import { requireAuth, requireRole } from "../middleware/auth.js";
|
||
import { upload, resolveFile, deleteFile, type MediaType } from "../services/storage.js";
|
||
|
||
export const mediaRouter = Router();
|
||
|
||
const STAFF_WRITE = requireRole("admin", "event_manager");
|
||
|
||
// ── Upload ─────────────────────────────────────────────────────────────────────
|
||
mediaRouter.post(
|
||
"/upload",
|
||
requireAuth,
|
||
STAFF_WRITE,
|
||
// Parse a single file field named "file" plus any text fields (itemId, mediaType)
|
||
upload.single("file"),
|
||
(req, res) => {
|
||
if (!req.file) {
|
||
res.status(400).json({ error: "No file received" });
|
||
return;
|
||
}
|
||
|
||
const mediaType = (req.body as { mediaType?: string }).mediaType as MediaType | undefined;
|
||
if (!mediaType || !["image", "video", "document"].includes(mediaType)) {
|
||
res.status(400).json({ error: "mediaType must be image, video, or document" });
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const saved = resolveFile(req.file, mediaType);
|
||
res.status(201).json(saved);
|
||
} catch (err) {
|
||
res.status(400).json({ error: String(err) });
|
||
}
|
||
},
|
||
);
|
||
|
||
// ── Delete ─────────────────────────────────────────────────────────────────────
|
||
mediaRouter.delete(
|
||
"/:key(*)", // key contains slashes, e.g. items/abc/uuid.jpg
|
||
requireAuth,
|
||
STAFF_WRITE,
|
||
async (req, res) => {
|
||
try {
|
||
await deleteFile(req.params["key"] ?? "");
|
||
res.json({ ok: true });
|
||
} catch (err) {
|
||
res.status(400).json({ error: String(err) });
|
||
}
|
||
},
|
||
);
|