192 lines
5.5 KiB
JavaScript
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
|
|
}; |