added image and audio REST endpoints

This commit is contained in:
Florian Zumpe
2026-06-16 23:52:37 +02:00
parent b910bce8df
commit c98f304ffa
13 changed files with 1126 additions and 494 deletions
+78 -4
View File
@@ -5,6 +5,10 @@ import {
listRoutes, getRoute, createRoute, updateRoute, appendRoute,
listPois, getPoi, createPoi, updatePoi, softDeleteRoute, restoreRoute
} from '../services/routes-service.js';
import {
listPictures, getPictureContent, createPicture, updatePicture, deletePicture,
listAudio, getAudioContent, createAudio, updateAudio, deleteAudio
} from '../services/media-service.js';
const numberOrUndefined = value => {
if (value == null || value === '') return undefined;
@@ -12,6 +16,26 @@ const numberOrUndefined = value => {
return Number.isFinite(parsed) ? parsed : undefined;
};
const positiveInteger = (value, name) => {
const parsed = Number.parseInt(value, 10);
if (!Number.isInteger(parsed) || parsed <= 0) {
const error = new Error(`${name} muss eine positive Ganzzahl sein.`);
error.status = 400;
throw error;
}
return parsed;
};
function sendMedia(res, resource) {
res.set({
'Cache-Control': 'private, max-age=60',
'Content-Disposition': `inline; filename="${resource.filename.replace(/["\\]/g, '_')}"`,
'X-Content-Type-Options': 'nosniff'
});
res.type(resource.contentType);
res.sendFile(resource.absolutePath);
}
export function createApiRouter(db) {
const api = Router();
@@ -61,13 +85,63 @@ export function createApiRouter(db) {
res.json(appendRoute(db, Number(req.params.id), req.file));
});
api.post('/routes/:id/pois', upload.fields([{ name: 'audio', maxCount: 1 }, { name: 'images', maxCount: 20 }]), (req, res) => {
const poi = createPoi(db, Number(req.params.id), req.body, req.files);
api.post('/routes/:id/pois', upload.none(), (req, res) => {
const poi = createPoi(db, Number(req.params.id), req.body);
res.status(201).location(`/api/pois/${poi.id}`).json(poi);
});
api.put('/pois/:id', upload.fields([{ name: 'audio', maxCount: 1 }, { name: 'images', maxCount: 20 }]), (req, res) => {
res.json(updatePoi(db, Number(req.params.id), req.body, req.files));
api.put('/pois/:id', upload.none(), (req, res) => {
res.json(updatePoi(db, Number(req.params.id), req.body));
});
api.get('/routes/:id/pictures', (req, res) => {
res.json({ pictures: listPictures(db, Number(req.params.id), { poiId: req.query.poiId }) });
});
api.get('/routes/:id/pictures/:pictureId', (req, res) => {
sendMedia(res, getPictureContent(db, Number(req.params.id), Number(req.params.pictureId)));
});
api.post('/routes/:id/pictures', upload.single('picture'), (req, res) => {
const picture = createPicture(db, Number(req.params.id), req.body, req.file);
res.status(201)
.location(`/api/routes/${req.params.id}/pictures/${picture.id}`)
.json(picture);
});
api.put('/routes/:id/pictures/:pictureId', upload.single('picture'), (req, res) => {
res.json(updatePicture(db, Number(req.params.id), Number(req.params.pictureId), req.body, req.file));
});
api.delete('/routes/:id/pictures/:pictureId', (req, res) => {
res.json(deletePicture(db, Number(req.params.id), Number(req.params.pictureId)));
});
api.get('/routes/:id/audio', (req, res) => {
if (req.query.poiId == null || req.query.poiId === '') {
res.json({ audio: listAudio(db, Number(req.params.id)) });
return;
}
const poiId = positiveInteger(req.query.poiId, 'poiId');
sendMedia(res, getAudioContent(db, Number(req.params.id), poiId));
});
api.post('/routes/:id/audio', upload.single('audio'), (req, res) => {
const audio = createAudio(db, Number(req.params.id), req.body, req.file);
res.status(201)
.location(`/api/routes/${req.params.id}/audio?poiId=${encodeURIComponent(audio.poiId)}`)
.json(audio);
});
api.put('/routes/:id/audio', upload.single('audio'), (req, res) => {
const poiId = positiveInteger(req.query.poiId ?? req.body.poiId, 'poiId');
res.json(updateAudio(db, Number(req.params.id), poiId, req.file));
});
api.delete('/routes/:id/audio', (req, res) => {
const poiId = positiveInteger(req.query.poiId ?? req.body?.poiId, 'poiId');
res.json(deleteAudio(db, Number(req.params.id), poiId));
});
api.delete('/routes/:id', (req, res) => {