181 lines
6.1 KiB
JavaScript
181 lines
6.1 KiB
JavaScript
import { Router } from 'express';
|
|
import { jsonUpload, upload } from '../middleware/upload.js';
|
|
import { config } from '../config.js';
|
|
import {
|
|
listRoutes, getRoute, getRouteGpxFile, createRoute, updateRoute, appendRoute,
|
|
listPois, getPoi, createPoi, updatePoi, softDeleteRoute, restoreRoute
|
|
} from '../services/routes-service.js';
|
|
import {
|
|
listPictures, getPicture, getPictureFile, createPicture, updatePicture, deletePicture,
|
|
getAudio, getAudioFile, createAudio, updateAudio, deleteAudio
|
|
} from '../services/media-service.js';
|
|
|
|
const numberOrUndefined = value => {
|
|
if (value == null || value === '') return undefined;
|
|
const parsed = Number.parseFloat(value);
|
|
return Number.isFinite(parsed) ? parsed : undefined;
|
|
};
|
|
|
|
function sendFileResource(res, file, contentType = null) {
|
|
if (contentType) res.type(contentType);
|
|
res.setHeader('Content-Disposition', `inline; filename*=UTF-8''${encodeURIComponent(file.filename)}`);
|
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
return res.sendFile(file.absolutePath, {
|
|
acceptRanges: true,
|
|
cacheControl: true,
|
|
immutable: false,
|
|
maxAge: '1h'
|
|
});
|
|
}
|
|
|
|
export function createApiRouter(db) {
|
|
const api = Router();
|
|
|
|
api.get('/health', (req, res) => {
|
|
const sqliteVersion = db.prepare('SELECT sqlite_version() AS version').get().version;
|
|
res.json({
|
|
ok: true,
|
|
service: 'wegwichtel',
|
|
socket: `${config.host}:${config.port}`,
|
|
sqliteVersion,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
});
|
|
|
|
api.get('/routes', (req, res) => {
|
|
res.json({ routes: listRoutes(db, {
|
|
lat: numberOrUndefined(req.query.lat),
|
|
lon: numberOrUndefined(req.query.lon),
|
|
radiusKm: numberOrUndefined(req.query.radiusKm),
|
|
includeDeleted: req.query.includeDeleted === 'true'
|
|
}) });
|
|
});
|
|
|
|
api.get('/routes/:id', (req, res) => {
|
|
res.json(getRoute(db, Number(req.params.id), req.query.includeDeleted === 'true'));
|
|
});
|
|
|
|
api.get('/routes/:id/gpx', (req, res) => {
|
|
sendFileResource(res, getRouteGpxFile(db, Number(req.params.id)), 'application/gpx+xml');
|
|
});
|
|
|
|
api.get('/routes/:id/pois', (req, res) => {
|
|
getRoute(db, Number(req.params.id));
|
|
res.json({ pois: listPois(db, Number(req.params.id)) });
|
|
});
|
|
|
|
api.get('/routes/:routeId/pois/:poiId', (req, res) => {
|
|
res.json(getPoi(db, Number(req.params.routeId), Number(req.params.poiId)));
|
|
});
|
|
|
|
api.post('/routes', upload.single('gpx'), (req, res) => {
|
|
const route = createRoute(db, req.body, req.file);
|
|
res.status(201).location(`/api/routes/${route.id}`).json(route);
|
|
});
|
|
|
|
api.put('/routes/:id', upload.single('gpx'), (req, res) => {
|
|
res.json(updateRoute(db, Number(req.params.id), req.body, req.file));
|
|
});
|
|
|
|
api.post('/routes/:id/append', upload.single('gpx'), (req, res) => {
|
|
res.json(appendRoute(db, Number(req.params.id), req.file));
|
|
});
|
|
|
|
api.post('/routes/:id/pois', upload.none(), (req, res) => {
|
|
const poi = createPoi(db, Number(req.params.id), req.body);
|
|
res.status(201)
|
|
.location(`/api/routes/${req.params.id}/pois/${poi.id}`)
|
|
.json(poi);
|
|
});
|
|
|
|
api.put('/routes/:routeId/pois/:poiId', upload.none(), (req, res) => {
|
|
res.json(updatePoi(
|
|
db,
|
|
Number(req.params.routeId),
|
|
Number(req.params.poiId),
|
|
req.body
|
|
));
|
|
});
|
|
|
|
api.get('/routes/:routeId/pois/:poiId/pictures', (req, res) => {
|
|
res.json({ pictures: listPictures(db, Number(req.params.routeId), Number(req.params.poiId)) });
|
|
});
|
|
|
|
api.get('/routes/:routeId/pois/:poiId/pictures/:pictureId', (req, res) => {
|
|
const routeId = Number(req.params.routeId);
|
|
const poiId = Number(req.params.poiId);
|
|
const pictureId = Number(req.params.pictureId);
|
|
if (req.query.metadata === 'true') {
|
|
res.json(getPicture(db, routeId, poiId, pictureId));
|
|
return;
|
|
}
|
|
sendFileResource(res, getPictureFile(db, routeId, poiId, pictureId));
|
|
});
|
|
|
|
api.post('/routes/:routeId/pois/:poiId/pictures', upload.single('picture'), jsonUpload('picture'), (req, res) => {
|
|
const routeId = Number(req.params.routeId);
|
|
const poiId = Number(req.params.poiId);
|
|
const picture = createPicture(db, routeId, poiId, req.body, req.file);
|
|
res.status(201)
|
|
.location(`/api/routes/${routeId}/pois/${poiId}/pictures/${picture.id}`)
|
|
.json(picture);
|
|
});
|
|
|
|
api.put('/routes/:routeId/pois/:poiId/pictures/:pictureId', upload.single('picture'), jsonUpload('picture'), (req, res) => {
|
|
res.json(updatePicture(
|
|
db,
|
|
Number(req.params.routeId),
|
|
Number(req.params.poiId),
|
|
Number(req.params.pictureId),
|
|
req.body,
|
|
req.file
|
|
));
|
|
});
|
|
|
|
api.delete('/routes/:routeId/pois/:poiId/pictures/:pictureId', (req, res) => {
|
|
res.json(deletePicture(
|
|
db,
|
|
Number(req.params.routeId),
|
|
Number(req.params.poiId),
|
|
Number(req.params.pictureId)
|
|
));
|
|
});
|
|
|
|
api.get('/routes/:routeId/pois/:poiId/audio', (req, res) => {
|
|
const routeId = Number(req.params.routeId);
|
|
const poiId = Number(req.params.poiId);
|
|
if (req.query.metadata === 'true') {
|
|
res.json(getAudio(db, routeId, poiId));
|
|
return;
|
|
}
|
|
sendFileResource(res, getAudioFile(db, routeId, poiId));
|
|
});
|
|
|
|
api.post('/routes/:routeId/pois/:poiId/audio', upload.single('audio'), jsonUpload('audio'), (req, res) => {
|
|
const routeId = Number(req.params.routeId);
|
|
const poiId = Number(req.params.poiId);
|
|
const audio = createAudio(db, routeId, poiId, req.file);
|
|
res.status(201)
|
|
.location(`/api/routes/${routeId}/pois/${poiId}/audio`)
|
|
.json(audio);
|
|
});
|
|
|
|
api.put('/routes/:routeId/pois/:poiId/audio', upload.single('audio'), jsonUpload('audio'), (req, res) => {
|
|
res.json(updateAudio(db, Number(req.params.routeId), Number(req.params.poiId), req.file));
|
|
});
|
|
|
|
api.delete('/routes/:routeId/pois/:poiId/audio', (req, res) => {
|
|
res.json(deleteAudio(db, Number(req.params.routeId), Number(req.params.poiId)));
|
|
});
|
|
|
|
api.delete('/routes/:id', (req, res) => {
|
|
res.json({ route: softDeleteRoute(db, Number(req.params.id)), softDeleted: true });
|
|
});
|
|
|
|
api.post('/routes/:id/restore', (req, res) => {
|
|
res.json({ route: restoreRoute(db, Number(req.params.id)), restored: true });
|
|
});
|
|
|
|
return api;
|
|
}
|