Release v2.4.2

This commit is contained in:
2026-08-03 12:45:27 +01:00
parent 2b9cabdab2
commit e95928f31c
141 changed files with 7694 additions and 5078 deletions
+38 -44
View File
@@ -2,7 +2,8 @@
const fs = require('fs');
const path = require('path');
const { loadFontLibrary } = require('../../lib/media/font-library');
const { loadFontLibrary } = require('#src/web/lib/media/font-library');
const { PERMISSION_DENIED_MESSAGE } = require('#src/rbac');
module.exports = function registerContentRoutes(app, deps) {
const pool = deps.pool;
@@ -27,12 +28,39 @@ module.exports = function registerContentRoutes(app, deps) {
const getCanvasSizeDeleteBlockMessage = deps.getCanvasSizeDeleteBlockMessage;
const requirePermission = deps.requirePermission;
const hasAnyPermission = deps.hasAnyPermission;
const { buildPagination } = require('../../lib/pagination');
const { buildPagination } = require('#src/web/lib/pagination');
const LIST_PAGE_SIZE = 25;
const IMAGE_UPLOAD_MAX_BYTES = 100 * 1024 * 1024;
const VIDEO_UPLOAD_MAX_BYTES = 1024 * 1024 * 1024;
async function fetchSlideFormData() {
const data = await common.fetchTemplatesData(pool);
const rssData = await common.fetchRssFeedsData(pool);
const apiData = typeof common.fetchApiSourcesData === 'function' ? await common.fetchApiSourcesData(pool) : { apiSources: [] };
const timetableData = typeof common.fetchTimetablesData === 'function' ? await common.fetchTimetablesData(pool) : { timetableGroups: [] };
const apiSources = Array.isArray(apiData.apiSources) ? apiData.apiSources.map(function (source) {
return Object.assign({}, source, {
responseJson: typeof common.parseJsonSafe === 'function' ? common.parseJsonSafe(source.last_response_json) : null
});
}) : [];
const rssFeeds = await Promise.all((rssData.rssFeeds || []).map(async function (feed) {
const items = typeof common.fetchRssFeedItemsByFeedId === 'function'
? await common.fetchRssFeedItemsByFeedId(pool, feed.id)
: [];
return Object.assign({}, feed, { items: items.map(function (item) {
return typeof common.normalizeRssFeedItem === 'function' ? common.normalizeRssFeedItem(item) : item;
}) });
}));
return Object.assign(data, rssData, apiData, timetableData, {
rssFeeds: rssFeeds,
apiSources: apiSources,
timetableGroups: timetableData.timetableGroups || [],
fontLibrary: loadFontLibrary(deps.uploadDir)
});
}
if (!pool || !common || !pages || !upload || typeof fetchScreensBySlideId !== 'function' || typeof fetchScreensByTemplateId !== 'function' || typeof collectUploadReferencesFromSlide !== 'function' || typeof collectUploadReferencesFromTemplate !== 'function' || typeof collectUploadReferencesFromPayload !== 'function' || typeof removeUnusedUploadFiles !== 'function' || typeof syncPlaylistUploadsOnChange !== 'function' || typeof getAuditUserId !== 'function' || typeof redirectAfterSave !== 'function' || typeof notifyPlayerScreens !== 'function' || typeof broadcastDashboardState !== 'function' || typeof getSlideDeleteBlockMessage !== 'function' || typeof getTemplateDeleteBlockMessage !== 'function' || typeof getCanvasSizeDeleteBlockMessage !== 'function' || typeof hasAnyPermission !== 'function') {
throw new Error('registerContentRoutes requires the content route dependencies.');
}
@@ -68,7 +96,7 @@ module.exports = function registerContentRoutes(app, deps) {
return next();
}
const error = new Error('You do not have permission to access this area.');
const error = new Error(PERMISSION_DENIED_MESSAGE);
error.statusCode = 403;
error.expose = true;
next(error);
@@ -271,25 +299,8 @@ module.exports = function registerContentRoutes(app, deps) {
app.get('/slides/new', requirePermission('slides.create'), async function (req, res, next) {
try {
const data = await common.fetchTemplatesData(pool);
const rssData = await common.fetchRssFeedsData(pool);
const apiData = typeof common.fetchApiSourcesData === 'function' ? await common.fetchApiSourcesData(pool) : { apiSources: [] };
const scheduleData = typeof common.fetchSchedulesData === 'function' ? await common.fetchSchedulesData(pool) : { scheduleGroups: [] };
const apiSources = Array.isArray(apiData.apiSources) ? apiData.apiSources.map(function (source) {
return Object.assign({}, source, {
responseJson: typeof common.parseJsonSafe === 'function' ? common.parseJsonSafe(source.last_response_json) : null
});
}) : [];
const rssFeeds = await Promise.all((rssData.rssFeeds || []).map(async function (feed) {
const items = typeof common.fetchRssFeedItemsByFeedId === 'function'
? await common.fetchRssFeedItemsByFeedId(pool, feed.id)
: [];
return Object.assign({}, feed, { items: items.map(function (item) {
return typeof common.normalizeRssFeedItem === 'function' ? common.normalizeRssFeedItem(item) : item;
}) });
}));
Object.assign(data, rssData, apiData, scheduleData, { rssFeeds: rssFeeds, apiSources: apiSources, scheduleGroups: scheduleData.scheduleGroups || [], fontLibrary: loadFontLibrary(deps.uploadDir) });
res.send(pages.renderSlideFormPage(data, 'create', null, req.query.message ? String(req.query.message) : '', req.currentUser));
const data = await fetchSlideFormData();
res.send(pages.renderSlideAddPage(data, req.query.message ? String(req.query.message) : '', req.currentUser));
} catch (error) {
next(error);
}
@@ -302,25 +313,8 @@ module.exports = function registerContentRoutes(app, deps) {
return res.status(404).send('Slide not found');
}
slide.inUse = Boolean(await getSlideDeleteBlockMessage(pool, slide));
const data = await common.fetchTemplatesData(pool);
const rssData = await common.fetchRssFeedsData(pool);
const apiData = typeof common.fetchApiSourcesData === 'function' ? await common.fetchApiSourcesData(pool) : { apiSources: [] };
const scheduleData = typeof common.fetchSchedulesData === 'function' ? await common.fetchSchedulesData(pool) : { scheduleGroups: [] };
const apiSources = Array.isArray(apiData.apiSources) ? apiData.apiSources.map(function (source) {
return Object.assign({}, source, {
responseJson: typeof common.parseJsonSafe === 'function' ? common.parseJsonSafe(source.last_response_json) : null
});
}) : [];
const rssFeeds = await Promise.all((rssData.rssFeeds || []).map(async function (feed) {
const items = typeof common.fetchRssFeedItemsByFeedId === 'function'
? await common.fetchRssFeedItemsByFeedId(pool, feed.id)
: [];
return Object.assign({}, feed, { items: items.map(function (item) {
return typeof common.normalizeRssFeedItem === 'function' ? common.normalizeRssFeedItem(item) : item;
}) });
}));
Object.assign(data, rssData, apiData, scheduleData, { rssFeeds: rssFeeds, apiSources: apiSources, scheduleGroups: scheduleData.scheduleGroups || [], fontLibrary: loadFontLibrary(deps.uploadDir) });
res.send(pages.renderSlideFormPage(data, 'edit', slide, req.query.message ? String(req.query.message) : '', req.currentUser));
const data = await fetchSlideFormData();
res.send(pages.renderSlideEditPage(data, slide, req.query.message ? String(req.query.message) : '', req.currentUser));
} catch (error) {
next(error);
}
@@ -484,7 +478,7 @@ module.exports = function registerContentRoutes(app, deps) {
app.get('/templates/new', requirePermission('templates.create'), async function (req, res, next) {
try {
const data = await common.fetchCanvasSizesData(pool);
res.send(pages.renderTemplateFormPage(null, 'create', req.query.message ? String(req.query.message) : '', data.canvasSizes, req.currentUser));
res.send(pages.renderTemplateAddPage(null, req.query.message ? String(req.query.message) : '', data.canvasSizes, req.currentUser));
} catch (error) {
next(error);
}
@@ -536,7 +530,7 @@ module.exports = function registerContentRoutes(app, deps) {
template.region_usage = await fetchTemplateRegionUsage(template);
template.inUse = (await fetchSlidesByTemplateId(template.id)).length > 0;
const sizeData = await common.fetchCanvasSizesData(pool);
res.send(pages.renderTemplateFormPage(template, 'edit', req.query.message ? String(req.query.message) : '', sizeData.canvasSizes, req.currentUser));
res.send(pages.renderTemplateEditPage(template, sizeData, req.query.message ? String(req.query.message) : '', req.currentUser));
} catch (error) {
next(error);
}
@@ -642,7 +636,7 @@ module.exports = function registerContentRoutes(app, deps) {
});
app.get('/canvas-sizes/new', requirePermission('canvas-sizes.create'), function (req, res) {
res.send(pages.renderCanvasSizeFormPage(null, 'create', req.query.message ? String(req.query.message) : '', req.currentUser));
res.send(pages.renderCanvasSizeAddPage(null, req.query.message ? String(req.query.message) : '', req.currentUser));
});
app.post('/canvas-sizes', requirePermission('canvas-sizes.create'), async function (req, res, next) {