Release 2.8.1
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m16s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 33s

This commit is contained in:
2026-08-16 22:08:32 +01:00
parent 203d0bfc01
commit a5bf8e6f7f
21 changed files with 227 additions and 60 deletions
+1 -1
View File
@@ -76,5 +76,5 @@ test('save app settings writes only supplied keys in one transaction', async ()
assert.equal(queries[0], 'begin');
assert.equal(queries[queries.length - 2], 'commit');
assert.equal(queries[queries.length - 1], 'release');
assert.equal(queries.filter(function (entry) { return entry && entry.sql; }).length, 1);
assert.equal(queries.filter(function (entry) { return entry && entry.sql; }).length, 2);
});
+2 -2
View File
@@ -17,7 +17,7 @@ test('player registry upserts include the identifier field', async () => {
if (String(sql || '').includes('information_schema.COLUMNS')) {
return [[{ column_count: 1 }]];
}
if (String(sql || '').includes('INSERT INTO d_players')) {
if (String(sql || '').includes('UPDATE d_players')) {
return [{ affectedRows: 1 }];
}
if (String(sql || '').includes('SELECT id, identifier, public_base_url, internal_base_url, last_seen_at')) {
@@ -63,5 +63,5 @@ test('player registry upserts include the identifier field', async () => {
}));
assert.deepEqual((calls.find(function (call) {
return /INSERT INTO d_players/.test(String(call.sql || ''));
}) || {}).params, ['Shop2', 'http://player.local', 'http://player:8081']);
}) || {}).params, ['Shop2', 'http://player.local', 'http://player:8081', 'Shop2']);
});
+17 -1
View File
@@ -5,7 +5,7 @@ const fs = require('node:fs');
const rbacPermissionsScript = fs.readFileSync(require.resolve('../src/web/public/js/rbac-permissions.js'), 'utf8');
const rbacFormTemplate = fs.readFileSync(require.resolve('../src/web/views/settings/rbac/form.hbs'), 'utf8');
const rbacRoutesSource = fs.readFileSync(require.resolve('../src/web/routes/admin/rbac.js'), 'utf8');
const { buildPermissionSections } = require('../src/web/routes/settings/rbac/form-view-model');
const { buildPermissionSections, buildRbacEditViewModel } = require('../src/web/routes/settings/rbac/form-view-model');
const rbacFormViewModel = fs.readFileSync(require.resolve('../src/web/routes/settings/rbac/form-view-model.js'), 'utf8');
const rbacSource = fs.readFileSync(require.resolve('../src/rbac.js'), 'utf8');
@@ -111,4 +111,20 @@ test('rbac duplicate route exists', () => {
assert.ok(rbacRoutes.includes("requirePermission('rbac.create')"));
assert.ok(duplicateHelpers.includes('buildDuplicateRoleName'));
assert.ok(duplicateHelpers.includes('buildDuplicateRole'));
});
test('built-in Super Admin role cannot be deleted but can be renamed', () => {
const model = buildRbacEditViewModel({
id: 1,
role_key: 'super-admin',
name: 'Super Admin',
inUse: false
}, '', null, [], [], null);
assert.equal(model.footerDeleteDisabled, true);
assert.equal(model.role.isProtected, true);
assert.equal(model.footerDeleteTitle, 'The built-in Super Admin role cannot be deleted.');
assert.equal(model.footerDeleteConfirmMessage, 'Delete Super Admin?');
assert.ok(!rbacFormTemplate.includes('The built-in role name cannot be changed.'));
assert.ok(!rbacFormTemplate.includes('The built-in role description cannot be changed.'));
});
+41
View File
@@ -76,4 +76,45 @@ test('pending migrations are reported when an older schema still needs scripts',
assert.ok(pendingMigrations.length > 0);
assert.equal(pendingMigrations.filter(function (migration) { return migration.version.indexOf('2.8.') === 0; }).length, 1);
assert.equal(pendingMigrations.find(function (migration) { return migration.version.indexOf('2.8.') === 0; }).version, '2.8.0');
});
test('a partial timetable schema does not fast-forward migration detection', async () => {
const pool = createPool([
{
match(sql) {
return sql.includes('FROM information_schema.COLUMNS') && sql.includes('TABLE_NAME = ?') && sql.includes('COLUMN_NAME = ?');
},
result: [[{ column_count: 0 }]]
},
{
match(_sql, params) {
return Array.isArray(params) && params[0] === 'i_timetable_groups';
},
result: [[{ table_count: 1 }]]
},
{
match(_sql, params) {
return Array.isArray(params) && params[0] === 'i_timetable_entries';
},
result: [[{ table_count: 0 }]]
},
{
match(_sql, params) {
return Array.isArray(params) && params[0] === 'i_schedule_groups';
},
result: [[{ table_count: 0 }]]
},
{
match(_sql, params) {
return Array.isArray(params) && params[0] === 'i_schedule_entries';
},
result: [[{ table_count: 0 }]]
}
]);
const pendingMigrations = await getPendingMigrations(pool, { currentVersion: '0.0.0' });
assert.ok(pendingMigrations.some(function (migration) { return migration.version === '2.6.16'; }));
assert.ok(pendingMigrations.some(function (migration) { return migration.version === '2.6.17'; }));
assert.ok(pendingMigrations.some(function (migration) { return migration.version === '2.6.18'; }));
});