185 lines
6.9 KiB
JavaScript
185 lines
6.9 KiB
JavaScript
// Screen route registration and dashboard wiring.
|
|
|
|
const fs = require('fs');
|
|
|
|
module.exports = function registerScreensRoutes(app, deps) {
|
|
const pool = deps.pool;
|
|
const common = deps.common;
|
|
const pages = deps.pages;
|
|
const buildDashboardState = deps.buildDashboardState;
|
|
const getScreenDeleteBlockMessage = deps.getScreenDeleteBlockMessage;
|
|
const { buildPagination } = require('../../../lib/pagination');
|
|
const requirePermission = deps.requirePermission;
|
|
|
|
const LIST_PAGE_SIZE = 25;
|
|
const batTemplatePath = require.resolve('#root/scripts/pulse-signage-kiosk.bat');
|
|
const shTemplatePath = require.resolve('#root/scripts/pulse-signage-kiosk.sh');
|
|
const launcherDownloadPaths = {
|
|
windows: '/downloads/kiosk/pulse-signage-kiosk.bat',
|
|
linux: '/downloads/kiosk/pulse-signage-kiosk.sh'
|
|
};
|
|
|
|
function normalizeTargetPlayerUrl(value) {
|
|
const normalized = String(value || '').trim().replace(/\/$/, '');
|
|
if (!normalized) {
|
|
return null;
|
|
}
|
|
if (!/^https?:\/\//i.test(normalized)) {
|
|
return null;
|
|
}
|
|
return normalized;
|
|
}
|
|
|
|
function requireQueryPermission(readPermissionKey, editPermissionKey) {
|
|
return function (req, res, next) {
|
|
const permissionKey = req.query && req.query.edit ? editPermissionKey : readPermissionKey;
|
|
return requirePermission(permissionKey)(req, res, next);
|
|
};
|
|
}
|
|
|
|
function applyConnectionCounts(screens, dashboardScreens) {
|
|
const countsById = new Map();
|
|
const countsBySlug = new Map();
|
|
const dashboardScreenBySlug = new Map();
|
|
|
|
(dashboardScreens || []).forEach(function (screen) {
|
|
const count = Number(screen && screen.player_connection_count || 0);
|
|
const id = screen && screen.id !== undefined && screen.id !== null ? String(screen.id) : '';
|
|
const slug = String(screen && screen.slug || '').trim();
|
|
|
|
if (id) {
|
|
countsById.set(id, count);
|
|
}
|
|
if (slug) {
|
|
countsBySlug.set(slug, count);
|
|
dashboardScreenBySlug.set(slug, screen);
|
|
}
|
|
if (id) {
|
|
dashboardScreenBySlug.set(id, screen);
|
|
}
|
|
});
|
|
|
|
return (screens || []).map(function (screen) {
|
|
const slug = String(screen && screen.slug || '').trim();
|
|
const id = screen && screen.id !== undefined && screen.id !== null ? String(screen.id) : '';
|
|
const dashboardScreen = dashboardScreenBySlug.get(slug) || dashboardScreenBySlug.get(id) || null;
|
|
const playerConnectionCount = countsBySlug.has(slug)
|
|
? countsBySlug.get(slug)
|
|
: countsById.get(id) || 0;
|
|
|
|
return Object.assign({}, screen, {
|
|
player_connection_count: playerConnectionCount,
|
|
});
|
|
});
|
|
}
|
|
|
|
async function buildPlayerUrl() {
|
|
if (typeof common.fetchPlayerPublicBaseUrl !== 'function') {
|
|
return null;
|
|
}
|
|
|
|
return common.fetchPlayerPublicBaseUrl(pool);
|
|
}
|
|
|
|
function buildLauncherContent(templatePath, playerUrl) {
|
|
const template = fs.readFileSync(templatePath, 'utf8');
|
|
const normalizedPlayerUrl = String(playerUrl || '').trim();
|
|
if (!normalizedPlayerUrl) {
|
|
return null;
|
|
}
|
|
|
|
if (template.indexOf('http://localhost:8081') === -1) {
|
|
throw new Error(`Launcher template is missing the default player URL placeholder: ${templatePath}`);
|
|
}
|
|
|
|
return template.replace('http://localhost:8081', normalizedPlayerUrl);
|
|
}
|
|
|
|
function sendLauncherDownload(res, fileName, content) {
|
|
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
res.set('Pragma', 'no-cache');
|
|
res.attachment(fileName);
|
|
res.type('text/plain; charset=utf-8');
|
|
res.send(content);
|
|
}
|
|
|
|
app.get('/screens', requireQueryPermission('screens.read', 'screens.update'), async function (req, res, next) {
|
|
try {
|
|
if (req.query.edit) {
|
|
const screen = await common.fetchScreenById(pool, Number(req.query.edit));
|
|
if (!screen) {
|
|
return res.status(404).send('Screen not found');
|
|
}
|
|
screen.inUse = Boolean(await getScreenDeleteBlockMessage(pool, screen, deps.getScreenConnections));
|
|
const editData = await common.fetchScreenEditData(pool);
|
|
return res.send(pages.renderScreenEditPage(screen, editData, req.query.message ? String(req.query.message) : '', req.currentUser));
|
|
}
|
|
const page = Math.max(1, Math.floor(Number(req.query.page) || 1));
|
|
const search = common.getSearchQuery(req);
|
|
const sort = common.getSortQuery(req);
|
|
const direction = common.getSortDirectionQuery(req);
|
|
const dashboardState = await buildDashboardState(pool);
|
|
const data = await common.fetchScreensPage(pool, page, LIST_PAGE_SIZE, search, sort, direction);
|
|
res.send(pages.renderScreensPage({
|
|
screens: applyConnectionCounts(data.screens || [], dashboardState.screens || []),
|
|
pagination: buildPagination(data.totalItems, data.currentPage, 'page', { search: search, sort: sort, direction: direction }, LIST_PAGE_SIZE, 'screens', 'Screen pages')
|
|
}, req.query.message ? String(req.query.message) : '', req.currentUser));
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
app.get('/screens/:id/edit', requirePermission('screens.update'), async function (req, res, next) {
|
|
try {
|
|
const screen = await common.fetchScreenById(pool, Number(req.params.id));
|
|
if (!screen) {
|
|
return res.status(404).send('Screen not found');
|
|
}
|
|
screen.inUse = Boolean(await getScreenDeleteBlockMessage(pool, screen, deps.getScreenConnections));
|
|
const editData = await common.fetchScreenEditData(pool);
|
|
return res.send(pages.renderScreenEditPage(screen, editData, req.query.message ? String(req.query.message) : '', req.currentUser));
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
app.get('/downloads/kiosk/pulse-signage-kiosk.bat', requirePermission('screens.update'), async function (_req, res, next) {
|
|
try {
|
|
const playerUrl = normalizeTargetPlayerUrl(_req.query && _req.query.playerUrl)
|
|
|| await buildPlayerUrl();
|
|
if (!playerUrl) {
|
|
return res.status(404).send('Player URL is not available yet.');
|
|
}
|
|
|
|
const content = buildLauncherContent(batTemplatePath, playerUrl);
|
|
if (!content) {
|
|
return res.status(404).send('Launcher template is not available.');
|
|
}
|
|
|
|
sendLauncherDownload(res, 'pulse-signage-kiosk.bat', content);
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
app.get('/downloads/kiosk/pulse-signage-kiosk.sh', requirePermission('screens.update'), async function (_req, res, next) {
|
|
try {
|
|
const playerUrl = normalizeTargetPlayerUrl(_req.query && _req.query.playerUrl)
|
|
|| await buildPlayerUrl();
|
|
if (!playerUrl) {
|
|
return res.status(404).send('Player URL is not available yet.');
|
|
}
|
|
|
|
const content = buildLauncherContent(shTemplatePath, playerUrl);
|
|
if (!content) {
|
|
return res.status(404).send('Launcher template is not available.');
|
|
}
|
|
|
|
sendLauncherDownload(res, 'pulse-signage-kiosk.sh', content);
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
};
|
|
|