Release 2.8.0
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m49s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 32s

This commit is contained in:
2026-08-16 17:15:31 +01:00
parent 1bdc122995
commit 203d0bfc01
105 changed files with 4185 additions and 677 deletions
+9 -1
View File
@@ -1,5 +1,7 @@
// Playlist admin routes and playlist-slide management.
const { fetchAppSettings } = require('../../../data/app-settings');
module.exports = function registerPlaylistRoutes(app, deps) {
const pool = deps.pool;
const common = deps.common;
@@ -9,6 +11,7 @@ module.exports = function registerPlaylistRoutes(app, deps) {
const fetchPlaylistCanvasId = deps.fetchPlaylistCanvasId;
const readArrayField = deps.readArrayField;
const getAuditUserId = deps.getAuditUserId;
const recordRequestAuditEvent = deps.recordRequestAuditEvent;
const redirectAfterSave = deps.redirectAfterSave;
const notifyPlayerScreens = deps.notifyPlayerScreens;
const broadcastDashboardState = deps.broadcastDashboardState;
@@ -295,6 +298,7 @@ module.exports = function registerPlaylistRoutes(app, deps) {
};
await savePlaylistItems(connection, playlist, req.body, actorId, { updatePlaylist: false });
await connection.commit();
if (typeof recordRequestAuditEvent === 'function') await recordRequestAuditEvent(pool, req, { category: 'playlists', eventType: 'playlist.created', actorUserId: actorId, targetType: 'playlist', targetId: result.insertId, targetLabel: name });
redirectAfterSave(req, res, '/playlists/' + result.insertId + '/edit', {
closeUrl: '/playlists',
newUrl: '/playlists/new',
@@ -352,6 +356,7 @@ module.exports = function registerPlaylistRoutes(app, deps) {
await connection.commit();
await notifyPlayerScreens(saveResult.affectedScreens, 'refresh');
await broadcastDashboardState();
if (typeof recordRequestAuditEvent === 'function') await recordRequestAuditEvent(pool, req, { category: 'playlists', eventType: 'playlist.updated', actorUserId: actorId, targetType: 'playlist', targetId: playlist.id, targetLabel: name });
redirectAfterSave(req, res, '/playlists/' + playlist.id + '/edit', {
closeUrl: '/playlists',
newUrl: '/playlists/new',
@@ -383,6 +388,7 @@ module.exports = function registerPlaylistRoutes(app, deps) {
return res.redirect('/playlists?message=' + encodeURIComponent(blockMessage));
}
await pool.query('DELETE FROM c_playlists WHERE id = ?', [playlist.id]);
if (typeof recordRequestAuditEvent === 'function') await recordRequestAuditEvent(pool, req, { category: 'playlists', eventType: 'playlist.deleted', actorUserId: getAuditUserId(req), targetType: 'playlist', targetId: playlist.id, targetLabel: playlist.name });
res.redirect('/playlists?message=' + encodeURIComponent('Playlist deleted.'));
} catch (error) {
next(error);
@@ -411,7 +417,9 @@ module.exports = function registerPlaylistRoutes(app, deps) {
if (playlistCanvasId && slideCanvasId !== playlistCanvasId) {
return res.status(400).send('The slide canvas size must match the existing playlist items.');
}
const durationValue = Number(req.body.duration_seconds || 10);
const hasSubmittedDuration = req.body.duration_seconds !== undefined && String(req.body.duration_seconds).trim() !== '';
const settings = hasSubmittedDuration ? null : await fetchAppSettings(pool);
const durationValue = Number(hasSubmittedDuration ? req.body.duration_seconds : settings['player.default_slide_duration_seconds']);
const durationSeconds = Number.isFinite(durationValue) ? Math.max(0.001, Math.round(durationValue * 1000) / 1000) : 10;
const [positionRows] = await pool.query('SELECT COALESCE(MAX(position), -1) AS max_position FROM c_playlist_slides WHERE playlist_id = ?', [playlist.id]);
const nextPosition = Number(positionRows[0].max_position) + 1;