Prepare v2.0.0 release
This commit is contained in:
@@ -33,6 +33,24 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
throw new Error('registerAdminContentRoutes requires the content route dependencies.');
|
||||
}
|
||||
|
||||
async function removeMediaFile(uploadPath) {
|
||||
const normalizedPath = String(uploadPath || '').trim();
|
||||
if (!normalizedPath || !normalizedPath.startsWith('/media/')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mediaRoot = path.dirname(deps.uploadDir);
|
||||
const filePath = path.join(mediaRoot, normalizedPath.replace(/^\/+media\//, ''));
|
||||
|
||||
try {
|
||||
await fs.promises.unlink(filePath);
|
||||
} catch (error) {
|
||||
if (!error || error.code !== 'ENOENT') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function requireSlideUploadPermission(req, res, next) {
|
||||
if (!req.currentUser) {
|
||||
return res.redirect('/login?message=' + encodeURIComponent('Please sign in to continue.'));
|
||||
@@ -105,12 +123,12 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
}
|
||||
|
||||
async function fetchTemplateSlideCount(templateId) {
|
||||
const [rows] = await pool.query('SELECT COUNT(*) AS slide_count FROM slides WHERE template_id = ?', [templateId]);
|
||||
const [rows] = await pool.query('SELECT COUNT(*) AS slide_count FROM c_slides WHERE template_id = ?', [templateId]);
|
||||
return Number(rows[0] && rows[0].slide_count) || 0;
|
||||
}
|
||||
|
||||
async function fetchTemplateRegionUsage(template) {
|
||||
const [slides] = await pool.query('SELECT content_json FROM slides WHERE template_id = ?', [template.id]);
|
||||
const [slides] = await pool.query('SELECT content_json FROM c_slides WHERE template_id = ?', [template.id]);
|
||||
const usage = new Set();
|
||||
const regionKeys = new Set((Array.isArray(template && template.regions) ? template.regions : [])
|
||||
.map((region) => String(region && region.region_key || '').trim())
|
||||
@@ -136,7 +154,7 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
}
|
||||
|
||||
async function fetchSlidesByTemplateId(templateId) {
|
||||
const [slides] = await pool.query('SELECT id, thumbnail_path FROM slides WHERE template_id = ? ORDER BY id ASC', [templateId]);
|
||||
const [slides] = await pool.query('SELECT id, thumbnail_path FROM c_slides WHERE template_id = ? ORDER BY id ASC', [templateId]);
|
||||
return slides;
|
||||
}
|
||||
|
||||
@@ -195,7 +213,7 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
|
||||
async function canvasSizeExists(width, height, ignoreId) {
|
||||
const params = [width, height];
|
||||
let query = 'SELECT COUNT(*) AS count FROM canvas_sizes WHERE width = ? AND height = ?';
|
||||
let query = 'SELECT COUNT(*) AS count FROM c_canvas_sizes WHERE width = ? AND height = ?';
|
||||
if (ignoreId) {
|
||||
query += ' AND id <> ?';
|
||||
params.push(ignoreId);
|
||||
@@ -214,8 +232,8 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
|
||||
const [rows] = await pool.query(
|
||||
`SELECT s.slug, COUNT(ps.id) AS slide_count
|
||||
FROM screens s
|
||||
LEFT JOIN playlist_slides ps ON ps.playlist_id = s.playlist_id
|
||||
FROM d_screens s
|
||||
LEFT JOIN c_playlist_slides ps ON ps.playlist_id = s.playlist_id
|
||||
WHERE s.slug IN (?)
|
||||
GROUP BY s.id, s.slug`,
|
||||
[uniqueSlugs]
|
||||
@@ -334,13 +352,13 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
try {
|
||||
await validateUploadedFiles(req.files || []);
|
||||
const payload = await common.buildSlidePayload(pool, req, null);
|
||||
if (await common.fetchDuplicateName(pool, 'slides', payload.title, null, 'title')) {
|
||||
if (await common.fetchDuplicateName(pool, 'c_slides', payload.title, null, 'title')) {
|
||||
return res.status(400).send('A slide with that title already exists.');
|
||||
}
|
||||
const actorId = getAuditUserId(req);
|
||||
const [result] = await pool.query(
|
||||
'INSERT INTO slides (title, body, template_id, content_json, media_path, media_type, created_by, modified_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[payload.title, payload.body, payload.templateId, payload.contentJson, payload.mediaPath, payload.mediaType, actorId, actorId]
|
||||
'INSERT INTO c_slides (title, template_id, content_json, created_by, modified_by) VALUES (?, ?, ?, ?, ?)',
|
||||
[payload.title, payload.templateId, payload.contentJson, actorId, actorId]
|
||||
);
|
||||
await syncPlaylistUploadsOnChange({
|
||||
key: 'slide:create:' + result.insertId,
|
||||
@@ -372,14 +390,14 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
const screenSlideCounts = await fetchScreenSlideCountsBySlug(affectedScreens);
|
||||
const existingUploadRefs = collectUploadReferencesFromSlide(slide);
|
||||
const payload = await common.buildSlidePayload(pool, req, slide);
|
||||
if (await common.fetchDuplicateName(pool, 'slides', payload.title, slide.id, 'title')) {
|
||||
if (await common.fetchDuplicateName(pool, 'c_slides', payload.title, slide.id, 'title')) {
|
||||
return res.status(400).send('A slide with that title already exists.');
|
||||
}
|
||||
const nextUploadRefs = collectUploadReferencesFromPayload(payload);
|
||||
const actorId = getAuditUserId(req);
|
||||
await pool.query(
|
||||
'UPDATE slides SET title = ?, body = ?, template_id = ?, content_json = ?, media_path = ?, media_type = ?, modified_by = ? WHERE id = ?',
|
||||
[payload.title, payload.body, payload.templateId, payload.contentJson, payload.mediaPath, payload.mediaType, actorId, slide.id]
|
||||
'UPDATE c_slides SET title = ?, template_id = ?, content_json = ?, modified_by = ? WHERE id = ?',
|
||||
[payload.title, payload.templateId, payload.contentJson, actorId, slide.id]
|
||||
);
|
||||
await syncPlaylistUploadsOnChange({
|
||||
key: 'slide:update:' + slide.id,
|
||||
@@ -418,7 +436,8 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
const affectedScreens = await fetchScreensBySlideId(pool, slide.id);
|
||||
const screenSlideCounts = await fetchScreenSlideCountsBySlug(affectedScreens);
|
||||
const uploadRefs = collectUploadReferencesFromSlide(slide);
|
||||
await pool.query('DELETE FROM slides WHERE id = ?', [slide.id]);
|
||||
await pool.query('DELETE FROM c_slides WHERE id = ?', [slide.id]);
|
||||
await removeMediaFile(slide.thumbnail_path);
|
||||
await syncPlaylistUploadsOnChange({
|
||||
key: 'slide:delete:' + slide.id,
|
||||
pool: pool,
|
||||
@@ -463,18 +482,18 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
app.post('/templates', requirePermission('templates.create'), upload.any(), async function (req, res, next) {
|
||||
try {
|
||||
const payload = await common.buildTemplatePayload(pool, req, null);
|
||||
if (await common.fetchDuplicateName(pool, 'slide_templates', payload.name)) {
|
||||
if (await common.fetchDuplicateName(pool, 'c_templates', payload.name)) {
|
||||
return res.redirect('/templates/new?message=' + encodeURIComponent('A template with that name already exists.'));
|
||||
}
|
||||
const actorId = getAuditUserId(req);
|
||||
const [result] = await pool.query(
|
||||
'INSERT INTO slide_templates (name, canvas_size_id, background_image_path, background_color, created_by, modified_by) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
'INSERT INTO c_templates (name, canvas_size_id, background_image_path, background_color, created_by, modified_by) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[payload.name, payload.canvasSizeId, payload.backgroundImagePath, payload.backgroundColor, actorId, actorId]
|
||||
);
|
||||
for (let i = 0; i < payload.regions.length; i += 1) {
|
||||
const region = payload.regions[i];
|
||||
await pool.query(
|
||||
'INSERT INTO slide_template_regions (template_id, region_key, region_type, label, font_family, lock_ratio, x, y, width, height, z_index, created_by, modified_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
'INSERT INTO c_template_regions (template_id, region_key, region_type, label, font_family, lock_ratio, x, y, width, height, z_index, created_by, modified_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[result.insertId, region.region_key, region.region_type, region.label, region.font_family, region.lock_ratio, region.x, region.y, region.width, region.height, region.z_index, actorId, actorId]
|
||||
);
|
||||
}
|
||||
@@ -517,7 +536,7 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
template.region_usage = await fetchTemplateRegionUsage(template);
|
||||
const existingUploadRefs = collectUploadReferencesFromTemplate(template);
|
||||
const payload = await common.buildTemplatePayload(pool, req, template);
|
||||
if (await common.fetchDuplicateName(pool, 'slide_templates', payload.name, template.id)) {
|
||||
if (await common.fetchDuplicateName(pool, 'c_templates', payload.name, template.id)) {
|
||||
return res.redirect('/templates/' + template.id + '/edit?message=' + encodeURIComponent('A template with that name already exists.'));
|
||||
}
|
||||
const regionDeleteBlockMessage = await getTemplateRegionDeleteBlockMessage(template, payload.regions);
|
||||
@@ -528,14 +547,14 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
const affectedScreens = await fetchScreensByTemplateId(pool, template.id);
|
||||
const actorId = getAuditUserId(req);
|
||||
await pool.query(
|
||||
'UPDATE slide_templates SET name = ?, canvas_size_id = ?, background_image_path = ?, background_color = ?, modified_by = ? WHERE id = ?',
|
||||
'UPDATE c_templates SET name = ?, canvas_size_id = ?, background_image_path = ?, background_color = ?, modified_by = ? WHERE id = ?',
|
||||
[payload.name, payload.canvasSizeId, payload.backgroundImagePath, payload.backgroundColor, actorId, template.id]
|
||||
);
|
||||
await pool.query('DELETE FROM slide_template_regions WHERE template_id = ?', [template.id]);
|
||||
await pool.query('DELETE FROM c_template_regions WHERE template_id = ?', [template.id]);
|
||||
for (let i = 0; i < payload.regions.length; i += 1) {
|
||||
const region = payload.regions[i];
|
||||
await pool.query(
|
||||
'INSERT INTO slide_template_regions (template_id, region_key, region_type, label, font_family, lock_ratio, x, y, width, height, z_index, created_by, modified_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
'INSERT INTO c_template_regions (template_id, region_key, region_type, label, font_family, lock_ratio, x, y, width, height, z_index, created_by, modified_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[template.id, region.region_key, region.region_type, region.label, region.font_family, region.lock_ratio, region.x, region.y, region.width, region.height, region.z_index, actorId, actorId]
|
||||
);
|
||||
}
|
||||
@@ -575,9 +594,9 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
}
|
||||
const uploadRefs = collectUploadReferencesFromTemplate(template);
|
||||
const affectedScreens = await fetchScreensByTemplateId(pool, template.id);
|
||||
await pool.query('UPDATE slides SET template_id = NULL, modified_by = ? WHERE template_id = ?', [getAuditUserId(req), template.id]);
|
||||
await pool.query('DELETE FROM slide_template_regions WHERE template_id = ?', [template.id]);
|
||||
await pool.query('DELETE FROM slide_templates WHERE id = ?', [template.id]);
|
||||
await pool.query('UPDATE c_slides SET template_id = NULL, modified_by = ? WHERE template_id = ?', [getAuditUserId(req), template.id]);
|
||||
await pool.query('DELETE FROM c_template_regions WHERE template_id = ?', [template.id]);
|
||||
await pool.query('DELETE FROM c_templates WHERE id = ?', [template.id]);
|
||||
await syncPlaylistUploadsOnChange({
|
||||
key: 'template:delete:' + template.id,
|
||||
pool: pool,
|
||||
@@ -621,7 +640,7 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
return res.redirect('/canvas-sizes/new?message=' + encodeURIComponent('That canvas size already exists.'));
|
||||
}
|
||||
const actorId = getAuditUserId(req);
|
||||
const [result] = await pool.query('INSERT INTO canvas_sizes (name, width, height, created_by, modified_by) VALUES (?, ?, ?, ?, ?)', [payload.name, payload.width, payload.height, actorId, actorId]);
|
||||
const [result] = await pool.query('INSERT INTO c_canvas_sizes (name, width, height, created_by, modified_by) VALUES (?, ?, ?, ?, ?)', [payload.name, payload.width, payload.height, actorId, actorId]);
|
||||
redirectAfterSave(req, res, '/canvas-sizes/' + result.insertId + '/edit', {
|
||||
closeUrl: '/canvas-sizes',
|
||||
newUrl: '/canvas-sizes/new',
|
||||
@@ -657,7 +676,7 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
if (await canvasSizeExists(payload.width, payload.height, canvasSize.id)) {
|
||||
return res.redirect('/canvas-sizes/' + canvasSize.id + '/edit?message=' + encodeURIComponent('That canvas size already exists.'));
|
||||
}
|
||||
await pool.query('UPDATE canvas_sizes SET name = ?, width = ?, height = ?, modified_by = ? WHERE id = ?', [payload.name, payload.width, payload.height, getAuditUserId(req), canvasSize.id]);
|
||||
await pool.query('UPDATE c_canvas_sizes SET name = ?, width = ?, height = ?, modified_by = ? WHERE id = ?', [payload.name, payload.width, payload.height, getAuditUserId(req), canvasSize.id]);
|
||||
redirectAfterSave(req, res, '/canvas-sizes', {
|
||||
closeUrl: '/canvas-sizes',
|
||||
newUrl: '/canvas-sizes/new',
|
||||
@@ -678,8 +697,8 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
if (blockMessage) {
|
||||
return res.redirect('/canvas-sizes?message=' + encodeURIComponent(blockMessage));
|
||||
}
|
||||
await pool.query('UPDATE slide_templates SET canvas_size_id = NULL, modified_by = ? WHERE canvas_size_id = ?', [getAuditUserId(req), canvasSize.id]);
|
||||
await pool.query('DELETE FROM canvas_sizes WHERE id = ?', [canvasSize.id]);
|
||||
await pool.query('UPDATE c_templates SET canvas_size_id = NULL, modified_by = ? WHERE canvas_size_id = ?', [getAuditUserId(req), canvasSize.id]);
|
||||
await pool.query('DELETE FROM c_canvas_sizes WHERE id = ?', [canvasSize.id]);
|
||||
res.redirect('/canvas-sizes?message=' + encodeURIComponent('Canvas size deleted.'));
|
||||
} catch (error) {
|
||||
next(error);
|
||||
|
||||
Reference in New Issue
Block a user