39948-vm/backend/src/routes/project_ui_control_settings.js
2026-06-29 09:38:55 +02:00

187 lines
5.0 KiB
JavaScript

const express = require('express');
const passport = require('passport');
const db = require('../db/models');
const Project_ui_control_settingsService = require('../services/project_ui_control_settings');
const Project_ui_control_settingsDBApi = require('../db/api/project_ui_control_settings');
const { wrapAsync, commonErrorHandler, isUuidV4 } = require('../helpers');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
const RuntimePresentationAccessService = require('../services/runtime-presentation-access');
const router = express.Router();
const jwtAuth = passport.authenticate('jwt', { session: false });
const allowAuthenticatedRead = (req, _res, next) => {
if (['GET', 'OPTIONS'].includes(req.method)) {
req.isRuntimePublicRequest = true;
}
return next();
};
const getRuntimeProjectSlug = async (req) => {
if (req.runtimeContext?.headerProjectSlug) {
return req.runtimeContext.headerProjectSlug;
}
if (!isUuidV4(req.params.projectId)) {
return null;
}
const project = await db.projects.findByPk(req.params.projectId, {
attributes: ['slug'],
});
return project?.slug || null;
};
const requireProductionOrAuth = async (req, res, next) => {
const { environment } = req.params;
const isProduction = environment === 'production';
const isReadOnly = ['GET', 'OPTIONS'].includes(req.method);
let runtimeProjectSlug = null;
let isPrivateProductionPresentation = false;
try {
runtimeProjectSlug = await getRuntimeProjectSlug(req);
isPrivateProductionPresentation =
await RuntimePresentationAccessService.isPrivateProductionPresentation(
runtimeProjectSlug,
);
} catch (error) {
return next(error);
}
if (isProduction && isReadOnly && !isPrivateProductionPresentation) {
return next();
}
if (isProduction && isReadOnly && isPrivateProductionPresentation) {
return passport.authenticate(
'jwt',
{ session: false },
async (error, user) => {
if (error) return next(error);
if (!user) {
return res.status(401).send({ message: 'Authentication required' });
}
req.currentUser = user;
const canAccess =
await RuntimePresentationAccessService.canUserAccessPrivateProductionPresentation(
user,
runtimeProjectSlug,
);
if (!canAccess) {
return res
.status(403)
.send({ message: 'Presentation access denied' });
}
req.isRuntimePublicRequest = true;
return next();
},
)(req, res, next);
}
return jwtAuth(req, res, next);
};
router.use(allowAuthenticatedRead);
router.use(checkCrudPermissions('project_ui_control_settings'));
router.get(
'/project/:projectId/env/:environment',
requireProductionOrAuth,
wrapAsync(async (req, res) => {
const { projectId, environment } = req.params;
if (!isUuidV4(projectId)) {
return res.status(400).send({ message: 'Invalid project ID' });
}
if (!['dev', 'stage', 'production'].includes(environment)) {
return res.status(400).send({ message: 'Invalid environment' });
}
const settings =
await Project_ui_control_settingsService.findByProjectAndEnvironment(
projectId,
environment,
req.currentUser,
);
res.status(200).send(settings);
}),
);
router.put(
'/project/:projectId/env/:environment',
jwtAuth,
wrapAsync(async (req, res) => {
const { projectId, environment } = req.params;
if (!isUuidV4(projectId)) {
return res.status(400).send({ message: 'Invalid project ID' });
}
if (!['dev', 'stage', 'production'].includes(environment)) {
return res.status(400).send({ message: 'Invalid environment' });
}
const settings = await Project_ui_control_settingsService.upsertForProject(
projectId,
environment,
req.body.data || {},
req.currentUser,
);
res.status(200).send(settings);
}),
);
router.delete(
'/project/:projectId/env/:environment',
jwtAuth,
wrapAsync(async (req, res) => {
const { projectId, environment } = req.params;
if (!isUuidV4(projectId)) {
return res.status(400).send({ message: 'Invalid project ID' });
}
if (!['dev', 'stage', 'production'].includes(environment)) {
return res.status(400).send({ message: 'Invalid environment' });
}
const settings =
await Project_ui_control_settingsService.findByProjectAndEnvironment(
projectId,
environment,
req.currentUser,
);
if (settings) {
await Project_ui_control_settingsService.remove({
id: settings.id,
currentUser: req.currentUser,
runtimeContext: req.runtimeContext,
});
}
res.status(200).send({ success: true });
}),
);
router.get(
'/',
jwtAuth,
wrapAsync(async (req, res) => {
const payload = await Project_ui_control_settingsDBApi.findAll(req.query);
res.status(200).send(payload);
}),
);
router.use('/', commonErrorHandler);
module.exports = router;