Files
pulse-signage/src/web/lib/helpers.js
T
2026-07-25 02:29:19 +01:00

192 lines
5.5 KiB
JavaScript

const dashboardDateFormatter = new Intl.DateTimeFormat('en-US', {
month: 'short',
day: '2-digit',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
second: '2-digit'
});
function normalizeUploadRoot(uploadDir) {
return require('path').resolve(String(uploadDir || '').trim());
}
function formatDashboardDate(value) {
if (!value) {
return '';
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return '';
}
return dashboardDateFormatter.format(date);
}
function buildDashboardPayload(state) {
return JSON.stringify({
type: 'dashboard-state',
state: state
});
}
function readArrayField(body, keys) {
const searchKeys = Array.isArray(keys) ? keys : [keys];
for (let i = 0; i < searchKeys.length; i += 1) {
const key = searchKeys[i];
const value = body && Object.prototype.hasOwnProperty.call(body, key) ? body[key] : undefined;
if (Array.isArray(value)) {
return value.filter(function (item) {
return item !== undefined && item !== null && String(item).trim() !== '';
}).map(function (item) {
return String(item);
});
}
if (value !== undefined && value !== null && String(value).trim() !== '') {
return [String(value)];
}
}
return [];
}
function parseDateTimeLocal(value) {
if (!value) {
return null;
}
const date = new Date(String(value));
return Number.isNaN(date.getTime()) ? null : date;
}
function parseTimeLocal(value) {
const raw = String(value || '').trim();
if (!raw) {
return null;
}
if (!/^\d{2}:\d{2}(:\d{2})?$/.test(raw)) {
return null;
}
return raw.length === 5 ? raw + ':00' : raw;
}
function normalizeScheduleMode(value) {
const mode = String(value || 'always');
if (mode === 'dates' || mode === 'times') {
return mode;
}
return 'always';
}
function getAuditUserId(req) {
return req && req.currentUser ? Number(req.currentUser.id) : null;
}
function getCanvasSignature(width, height) {
const normalizedWidth = Number(width);
const normalizedHeight = Number(height);
if (!Number.isFinite(normalizedWidth) || !Number.isFinite(normalizedHeight)) {
return null;
}
return normalizedWidth + 'x' + normalizedHeight;
}
async function fetchPlaylistCanvasSignature(pool, playlistId) {
const [rows] = await pool.query(
`SELECT DISTINCT cs.width AS canvas_width, cs.height AS canvas_height
FROM playlist_slides ps
JOIN slides sl ON sl.id = ps.slide_id
LEFT JOIN slide_templates st ON st.id = sl.template_id
LEFT JOIN canvas_sizes cs ON cs.id = st.canvas_size_id
WHERE ps.playlist_id = ?
AND cs.width IS NOT NULL
AND cs.height IS NOT NULL`,
[playlistId]
);
const signatures = Array.from(new Set(rows.map(function (row) {
return getCanvasSignature(row.canvas_width, row.canvas_height);
}).filter(Boolean)));
if (!signatures.length) {
return null;
}
return signatures.length === 1 ? signatures[0] : 'mismatch';
}
async function fetchScreensByPlaylistId(connection, playlistId) {
const [rows] = await connection.query(
'SELECT slug FROM screens WHERE playlist_id = ? AND slug IS NOT NULL',
[playlistId]
);
return rows.map(function (row) {
return row.slug;
});
}
async function fetchScreensBySlideId(connection, slideId) {
const [rows] = await connection.query(
`SELECT DISTINCT s.slug
FROM screens s
JOIN playlist_slides ps ON ps.playlist_id = s.playlist_id
WHERE ps.slide_id = ?
AND s.slug IS NOT NULL`,
[slideId]
);
return rows.map(function (row) {
return row.slug;
});
}
async function fetchScreensByTemplateId(connection, templateId) {
const [rows] = await connection.query(
`SELECT DISTINCT s.slug
FROM screens s
JOIN playlist_slides ps ON ps.playlist_id = s.playlist_id
JOIN slides sl ON sl.id = ps.slide_id
WHERE sl.template_id = ?
AND s.slug IS NOT NULL`,
[templateId]
);
return rows.map(function (row) {
return row.slug;
});
}
async function fetchOrderedPlaylistSlides(connection, playlistId) {
const [rows] = await connection.query(
'SELECT id, position FROM playlist_slides WHERE playlist_id = ? ORDER BY position ASC, id ASC',
[playlistId]
);
return rows;
}
function redirectAfterSave(req, res, defaultUrl, options) {
const safeOptions = options || {};
const action = String((req && req.body && req.body.action) || req.query.action || '').toLowerCase();
if (action === 'close') {
return res.redirect(safeOptions.closeUrl || defaultUrl);
}
if (action === 'new') {
return res.redirect(safeOptions.newUrl || defaultUrl);
}
const message = safeOptions.message || '';
if (message) {
const joiner = defaultUrl.indexOf('?') === -1 ? '?' : '&';
return res.redirect(defaultUrl + joiner + 'message=' + encodeURIComponent(message));
}
return res.redirect(defaultUrl);
}
module.exports = {
normalizeUploadRoot: normalizeUploadRoot,
formatDashboardDate: formatDashboardDate,
buildDashboardPayload: buildDashboardPayload,
readArrayField: readArrayField,
parseDateTimeLocal: parseDateTimeLocal,
parseTimeLocal: parseTimeLocal,
normalizeScheduleMode: normalizeScheduleMode,
getAuditUserId: getAuditUserId,
getCanvasSignature: getCanvasSignature,
fetchPlaylistCanvasSignature: fetchPlaylistCanvasSignature,
fetchScreensByPlaylistId: fetchScreensByPlaylistId,
fetchScreensBySlideId: fetchScreensBySlideId,
fetchScreensByTemplateId: fetchScreensByTemplateId,
fetchOrderedPlaylistSlides: fetchOrderedPlaylistSlides,
redirectAfterSave: redirectAfterSave
};