Release v2.4.2
This commit is contained in:
+24
-3
@@ -14,7 +14,7 @@ async function fetchAdminData(pool) {
|
||||
`);
|
||||
const [templateRegions] = await pool.query('SELECT id, template_id, region_key, region_type, label, lock_ratio, x, y, width, height, z_index, created_at, modified_at, created_by, modified_by FROM c_template_regions ORDER BY template_id ASC, z_index ASC, id ASC');
|
||||
const [slides] = await pool.query(`
|
||||
SELECT s.id, s.title, s.template_id, s.content_json, s.thumbnail_path, s.created_at, s.modified_at, s.created_by, s.modified_by, st.name AS template_name, cs.width AS canvas_width, cs.height AS canvas_height,
|
||||
SELECT s.id, s.title, s.template_id, s.content_json, s.thumbnail_path, s.created_at, s.modified_at, s.created_by, s.modified_by, st.name AS template_name, st.canvas_size_id, cs.width AS canvas_width, cs.height AS canvas_height,
|
||||
(SELECT COUNT(DISTINCT ps.playlist_id) FROM c_playlist_slides ps WHERE ps.slide_id = s.id) AS playlist_count
|
||||
FROM c_slides s
|
||||
LEFT JOIN c_templates st ON st.id = s.template_id
|
||||
@@ -28,14 +28,35 @@ async function fetchAdminData(pool) {
|
||||
ORDER BY s.id DESC
|
||||
`);
|
||||
const [playlistSlides] = await pool.query(`
|
||||
SELECT ps.id, ps.playlist_id, ps.position, ps.duration_seconds, ps.use_video_duration, ps.schedule_mode, ps.schedule_start_datetime, ps.schedule_end_datetime, ps.schedule_start_time, ps.schedule_end_time, ps.schedule_days_json, sl.id AS slide_id, sl.title, sl.content_json, sl.thumbnail_path, cs.width AS canvas_width, cs.height AS canvas_height
|
||||
SELECT ps.id, ps.playlist_id, ps.position, ps.duration_seconds, ps.use_video_duration, ps.disable_audio, sl.id AS slide_id, sl.title, sl.content_json, sl.thumbnail_path, st.canvas_size_id, cs.width AS canvas_width, cs.height AS canvas_height
|
||||
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
|
||||
LEFT JOIN c_canvas_sizes cs ON cs.id = st.canvas_size_id
|
||||
ORDER BY ps.playlist_id ASC, ps.position ASC, ps.id ASC
|
||||
`);
|
||||
return { playlists, canvasSizes, templates, templateRegions, slides, screens, playlistSlides };
|
||||
const [playlistScheduleRules] = await pool.query(`
|
||||
SELECT id, playlist_slide_id, position, start_datetime, end_datetime, start_time, end_time, schedule_days_json, created_at, modified_at, created_by, modified_by
|
||||
FROM c_playlist_slide_schedule_rules
|
||||
ORDER BY playlist_slide_id ASC, position ASC, id ASC
|
||||
`);
|
||||
|
||||
const rulesBySlideId = new Map();
|
||||
playlistScheduleRules.forEach(function (rule) {
|
||||
const slideId = Number(rule.playlist_slide_id);
|
||||
if (!rulesBySlideId.has(slideId)) {
|
||||
rulesBySlideId.set(slideId, []);
|
||||
}
|
||||
rulesBySlideId.get(slideId).push(rule);
|
||||
});
|
||||
|
||||
const playlistSlidesWithRules = playlistSlides.map(function (slide) {
|
||||
return Object.assign({}, slide, {
|
||||
scheduleRules: rulesBySlideId.get(Number(slide.id)) || []
|
||||
});
|
||||
});
|
||||
|
||||
return { playlists, canvasSizes, templates, templateRegions, slides, screens, playlistSlides: playlistSlidesWithRules };
|
||||
}
|
||||
|
||||
async function fetchPlaylistsPage(pool, page, pageSize, searchTerm, sortKey, sortDirection) {
|
||||
|
||||
+6
-6
@@ -4,7 +4,7 @@ const { fetchAdminData, fetchPlaylistsPage, fetchSlidesPage, fetchTemplatesPage,
|
||||
const { ANNOUNCEMENT_TYPES, ANNOUNCEMENT_COLORS, ANNOUNCEMENT_ICONS, DEFAULT_ANNOUNCEMENT_ICON, normalizeAnnouncementType, normalizeAnnouncementColor, normalizeAnnouncementIcon, fetchAnnouncementsPage, fetchAnnouncementById, fetchActiveAnnouncement, buildAnnouncementPayload } = require('./announcements');
|
||||
const { ANNOUNCEMENT_ICON_OPTIONS, ANNOUNCEMENT_ICON_LABELS } = require('./announcement-icons');
|
||||
const { fetchPlaylistById } = require('./playlists');
|
||||
const { normalizeDisplayMode, fetchSchedulesData, fetchScheduleGroupsPage, fetchScheduleGroupById, fetchScheduleEntriesByGroupId, buildScheduleGroupPayload } = require('./schedules');
|
||||
const { normalizeDisplayMode, fetchTimetablesData, fetchTimetableGroupsPage, fetchTimetableGroupById, fetchTimetableEntriesByGroupId, buildTimetableGroupPayload } = require('./schedules');
|
||||
const { fetchApiSourcesData, fetchApiSourcesPage, fetchApiSourceById, fetchApiSourceResponse, buildApiSourcePayload } = require('./api-sources');
|
||||
const { fetchRssFeedsData, fetchRssFeedsPage, fetchRssFeedById, fetchRssFeedItemsByFeedId, normalizeRssFeedItem, buildRssFeedPayload, fetchRssFeedItems, replaceRssFeedItems } = require('./rss-feeds');
|
||||
const { slugify, uniqueScreenSlug, fetchScreenById, fetchScreenEditData, fetchScreenPlayerUrls, fetchScreenPlayerRecord } = require('./screens');
|
||||
@@ -38,11 +38,11 @@ module.exports = {
|
||||
buildAnnouncementPayload,
|
||||
fetchPlaylistById,
|
||||
normalizeDisplayMode,
|
||||
fetchSchedulesData,
|
||||
fetchScheduleGroupsPage,
|
||||
fetchScheduleGroupById,
|
||||
fetchScheduleEntriesByGroupId,
|
||||
buildScheduleGroupPayload,
|
||||
fetchTimetablesData,
|
||||
fetchTimetableGroupsPage,
|
||||
fetchTimetableGroupById,
|
||||
fetchTimetableEntriesByGroupId,
|
||||
buildTimetableGroupPayload,
|
||||
fetchApiSourcesData,
|
||||
fetchApiSourcesPage,
|
||||
fetchApiSourceById,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Playlist data access helpers.
|
||||
|
||||
async function fetchPlaylistById(pool, id) {
|
||||
const [rows] = await pool.query('SELECT id, name, fade_between_slides, skip_unavailable_rtmp, created_at, modified_at, created_by, modified_by FROM c_playlists WHERE id = ?', [id]);
|
||||
const [rows] = await pool.query('SELECT id, name, fade_between_slides, skip_unavailable_rtmp, canvas_id, created_at, modified_at, created_by, modified_by FROM c_playlists WHERE id = ?', [id]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
|
||||
+21
-21
@@ -1,4 +1,4 @@
|
||||
// Schedule group and entry data access helpers.
|
||||
// Timetable group and entry data access helpers.
|
||||
|
||||
const { fetchPagedRows } = require('./utils');
|
||||
|
||||
@@ -10,22 +10,22 @@ function normalizeDisplayMode(value) {
|
||||
return 'upcoming';
|
||||
}
|
||||
|
||||
async function fetchSchedulesData(pool) {
|
||||
const [scheduleGroups] = await pool.query(`
|
||||
async function fetchTimetablesData(pool) {
|
||||
const [timetableGroups] = await pool.query(`
|
||||
SELECT g.id, g.name, g.short_description, g.created_at, g.modified_at, g.created_by, g.modified_by,
|
||||
(SELECT COUNT(*) FROM i_schedule_entries e WHERE e.schedule_group_id = g.id) AS entry_count,
|
||||
(SELECT MIN(e.start_datetime) FROM i_schedule_entries e WHERE e.schedule_group_id = g.id AND e.start_datetime IS NOT NULL) AS next_start_datetime
|
||||
FROM i_schedule_groups g
|
||||
ORDER BY g.modified_at DESC, g.id DESC
|
||||
`);
|
||||
const [scheduleEntries] = await pool.query(`
|
||||
const [timetableEntries] = await pool.query(`
|
||||
SELECT id, schedule_group_id, title, short_description, start_datetime, end_datetime, created_at, modified_at, created_by, modified_by
|
||||
FROM i_schedule_entries
|
||||
ORDER BY schedule_group_id ASC, start_datetime ASC, id ASC
|
||||
`);
|
||||
|
||||
const entriesByGroupId = new Map();
|
||||
scheduleEntries.forEach(function (entry) {
|
||||
timetableEntries.forEach(function (entry) {
|
||||
const groupId = Number(entry.schedule_group_id);
|
||||
if (!entriesByGroupId.has(groupId)) {
|
||||
entriesByGroupId.set(groupId, []);
|
||||
@@ -33,19 +33,19 @@ async function fetchSchedulesData(pool) {
|
||||
entriesByGroupId.get(groupId).push(entry);
|
||||
});
|
||||
|
||||
const groups = scheduleGroups.map(function (group) {
|
||||
const groups = timetableGroups.map(function (group) {
|
||||
return Object.assign({}, group, {
|
||||
entries: entriesByGroupId.get(Number(group.id)) || []
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
scheduleGroups: groups,
|
||||
scheduleEntries: scheduleEntries
|
||||
timetableGroups: groups,
|
||||
timetableEntries: timetableEntries
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchScheduleGroupsPage(pool, page, pageSize, searchTerm, sortKey, sortDirection) {
|
||||
async function fetchTimetableGroupsPage(pool, page, pageSize, searchTerm, sortKey, sortDirection) {
|
||||
const paged = await fetchPagedRows(pool, {
|
||||
selectSql: `SELECT g.id, g.name, g.short_description, g.created_at, g.modified_at, g.created_by, g.modified_by,
|
||||
(SELECT COUNT(*) FROM i_schedule_entries e WHERE e.schedule_group_id = g.id) AS entry_count,
|
||||
@@ -69,10 +69,10 @@ async function fetchScheduleGroupsPage(pool, page, pageSize, searchTerm, sortKey
|
||||
pageSize: pageSize
|
||||
});
|
||||
|
||||
return Object.assign({ scheduleGroups: paged.rows }, paged);
|
||||
return Object.assign({ timetableGroups: paged.rows }, paged);
|
||||
}
|
||||
|
||||
async function fetchScheduleGroupById(pool, id) {
|
||||
async function fetchTimetableGroupById(pool, id) {
|
||||
const [rows] = await pool.query(
|
||||
'SELECT id, name, short_description, created_at, modified_at, created_by, modified_by FROM i_schedule_groups WHERE id = ?',
|
||||
[id]
|
||||
@@ -81,25 +81,25 @@ async function fetchScheduleGroupById(pool, id) {
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
async function fetchScheduleEntriesByGroupId(pool, scheduleGroupId) {
|
||||
async function fetchTimetableEntriesByGroupId(pool, timetableGroupId) {
|
||||
const [rows] = await pool.query(
|
||||
`SELECT id, schedule_group_id, title, short_description, start_datetime, end_datetime, created_at, modified_at, created_by, modified_by
|
||||
FROM i_schedule_entries
|
||||
WHERE schedule_group_id = ?
|
||||
ORDER BY start_datetime ASC, id ASC`,
|
||||
[scheduleGroupId]
|
||||
[timetableGroupId]
|
||||
);
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
function buildScheduleGroupPayload(req, existingScheduleGroup) {
|
||||
const fallback = existingScheduleGroup || {};
|
||||
function buildTimetableGroupPayload(req, existingTimetableGroup) {
|
||||
const fallback = existingTimetableGroup || {};
|
||||
const name = String(req.body.name || fallback.name || '').trim();
|
||||
const shortDescription = String(req.body.short_description || req.body.shortDescription || fallback.short_description || '').trim();
|
||||
|
||||
if (!name) {
|
||||
const error = new Error('Schedule group name is required.');
|
||||
const error = new Error('Timetable group name is required.');
|
||||
error.statusCode = 400;
|
||||
throw error;
|
||||
}
|
||||
@@ -112,9 +112,9 @@ function buildScheduleGroupPayload(req, existingScheduleGroup) {
|
||||
|
||||
module.exports = {
|
||||
normalizeDisplayMode,
|
||||
fetchSchedulesData,
|
||||
fetchScheduleGroupsPage,
|
||||
fetchScheduleGroupById,
|
||||
fetchScheduleEntriesByGroupId,
|
||||
buildScheduleGroupPayload
|
||||
fetchTimetablesData,
|
||||
fetchTimetableGroupsPage,
|
||||
fetchTimetableGroupById,
|
||||
fetchTimetableEntriesByGroupId,
|
||||
buildTimetableGroupPayload
|
||||
};
|
||||
+1
-1
@@ -49,7 +49,7 @@ function normalizeEditorMarkup(value) {
|
||||
async function fetchSlideById(pool, id) {
|
||||
const [slides] = await pool.query(`
|
||||
SELECT s.id, s.title, s.template_id, s.content_json, s.thumbnail_path, s.created_at, s.modified_at,
|
||||
st.name AS template_name, cs.name AS canvas_size_name, cs.width AS canvas_width, cs.height AS canvas_height
|
||||
st.name AS template_name, st.canvas_size_id, cs.name AS canvas_size_name, cs.width AS canvas_width, cs.height AS canvas_height
|
||||
FROM c_slides s
|
||||
LEFT JOIN c_templates st ON st.id = s.template_id
|
||||
LEFT JOIN c_canvas_sizes cs ON cs.id = st.canvas_size_id
|
||||
|
||||
Reference in New Issue
Block a user