207 lines
5.9 KiB
JavaScript
207 lines
5.9 KiB
JavaScript
// Shared helpers for dashboard date formatting, uploads, and query parsing.
|
|
|
|
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 fetchPlaylistCanvasId(pool, playlistId) {
|
|
const [playlistRows] = await pool.query('SELECT canvas_id FROM c_playlists WHERE id = ?', [playlistId]);
|
|
const storedCanvasId = Number(playlistRows && playlistRows[0] && playlistRows[0].canvas_id);
|
|
if (Number.isInteger(storedCanvasId) && storedCanvasId > 0) {
|
|
return storedCanvasId;
|
|
}
|
|
|
|
const [rows] = await pool.query(
|
|
`SELECT DISTINCT st.canvas_size_id AS canvas_id
|
|
FROM c_playlist_slides ps
|
|
JOIN c_slides sl ON sl.id = ps.slide_id
|
|
LEFT JOIN c_templates st ON st.id = sl.template_id
|
|
WHERE ps.playlist_id = ?
|
|
AND st.canvas_size_id IS NOT NULL`,
|
|
[playlistId]
|
|
);
|
|
const canvasIds = Array.from(new Set(rows.map(function (row) {
|
|
return Number(row.canvas_id);
|
|
}).filter(function (value) {
|
|
return Number.isInteger(value) && value > 0;
|
|
})));
|
|
if (!canvasIds.length) {
|
|
return null;
|
|
}
|
|
return canvasIds.length === 1 ? canvasIds[0] : 'mismatch';
|
|
}
|
|
|
|
async function fetchScreensByPlaylistId(connection, playlistId) {
|
|
const [rows] = await connection.query(
|
|
'SELECT slug FROM d_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 d_screens s
|
|
JOIN c_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 d_screens s
|
|
JOIN c_playlist_slides ps ON ps.playlist_id = s.playlist_id
|
|
JOIN c_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 c_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.body.save_action)) || req.query.action || '').toLowerCase();
|
|
const message = safeOptions.message || '';
|
|
|
|
function withMessage(url) {
|
|
if (!message) {
|
|
return url;
|
|
}
|
|
|
|
const joiner = String(url || '').indexOf('?') === -1 ? '?' : '&';
|
|
return url + joiner + 'message=' + encodeURIComponent(message);
|
|
}
|
|
|
|
if (action === 'close') {
|
|
return res.redirect(withMessage(safeOptions.closeUrl || defaultUrl));
|
|
}
|
|
if (action === 'new') {
|
|
return res.redirect(withMessage(safeOptions.newUrl || defaultUrl));
|
|
}
|
|
return res.redirect(withMessage(defaultUrl));
|
|
}
|
|
|
|
module.exports = {
|
|
normalizeUploadRoot: normalizeUploadRoot,
|
|
formatDashboardDate: formatDashboardDate,
|
|
buildDashboardPayload: buildDashboardPayload,
|
|
readArrayField: readArrayField,
|
|
parseDateTimeLocal: parseDateTimeLocal,
|
|
parseTimeLocal: parseTimeLocal,
|
|
normalizeScheduleMode: normalizeScheduleMode,
|
|
getAuditUserId: getAuditUserId,
|
|
getCanvasSignature: getCanvasSignature,
|
|
fetchPlaylistCanvasId: fetchPlaylistCanvasId,
|
|
fetchPlaylistCanvasSignature: fetchPlaylistCanvasId,
|
|
fetchScreensByPlaylistId: fetchScreensByPlaylistId,
|
|
fetchScreensBySlideId: fetchScreensBySlideId,
|
|
fetchScreensByTemplateId: fetchScreensByTemplateId,
|
|
fetchOrderedPlaylistSlides: fetchOrderedPlaylistSlides,
|
|
redirectAfterSave: redirectAfterSave
|
|
}; |