fix: preserve settings during cleanup
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m17s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 31s

This commit is contained in:
2026-09-04 22:16:43 +01:00
parent 48c007f7b2
commit 7fec2154e0
3 changed files with 15 additions and 2 deletions
+1
View File
@@ -25,6 +25,7 @@ All notable changes to this project will be documented in this file.
- Updated the invitation registration page to show fields only for valid tokens, use the themed failure state for invalid links, and pre-fill the invited email and display name.
- Made the invited email visibly disabled, kept the display name editable and required, and aligned invitation actions with the existing user forms.
- Added bold, italic, and underline formatting controls to the user invitation email message template editor.
- Fixed application-settings cleanup SQL so media and icon saves preserve all supported settings and no longer fail with MariaDB placeholder errors.
- Updated API progress bars to inherit the surrounding WYSIWYG text size and text color, preserve rounded corners, and render consistently in the editor preview, player, and thumbnails.
## 2.11.0 - 2026-09-02
+8 -2
View File
@@ -65,6 +65,12 @@ module.exports = function registerSettingsPageRoutes(app, deps) {
weather: ['weather.open_meteo_api_key', 'weather.pirate_weather_api_key'],
icons: ['announcements.suggested_icons']
};
const ALL_SETTING_KEYS = Object.keys(SECTION_SETTING_KEYS).reduce(function (keys, section) {
return keys.concat(SECTION_SETTING_KEYS[section].filter(function (key) {
return !keys.includes(key);
}));
}, []);
const ALL_SETTING_KEY_PLACEHOLDERS = ALL_SETTING_KEYS.map(function () { return '?'; }).join(', ');
function maskApiKey(value) {
const key = String(value || '');
@@ -496,7 +502,7 @@ module.exports = function registerSettingsPageRoutes(app, deps) {
error.expose = true;
throw error;
}
await pool.query('DELETE FROM o_app_settings WHERE setting_key NOT IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', ['announcements.suggested_icons', 'announcements.default_icon', 'announcements.default_duration_value', 'announcements.default_duration_unit', 'player.default_slide_duration_seconds', 'player.default_fade_between_slides', 'player.skip_unavailable_rtmp', 'data-sources.rss_default_interval_value', 'data-sources.rss_default_interval_unit', 'data-sources.api_default_interval_value', 'data-sources.api_default_interval_unit', 'weather.open_meteo_api_key', 'weather.pirate_weather_api_key', 'uploads.image_max_bytes', 'uploads.video_max_bytes', 'uploads.wysiwyg_image_max_bytes', 'uploads.allowed_mime_types', 'security.session_lifetime_days', 'security.allow_user_session_revocation', 'security.max_active_sessions', 'security.login_max_attempts', 'security.login_lockout_minutes', 'security.login_rate_limit_scope', 'security.password_min_length', 'security.password_min_categories', 'security.password_require_lowercase', 'security.password_require_uppercase', 'security.password_require_number', 'security.password_require_symbol', 'security.require_password_change_for_new_users', 'security.require_password_change_after_admin_reset', 'security.allow_admin_email_verification_bypass', 'email.smtp_enabled', 'email.smtp_host', 'email.smtp_port', 'email.smtp_security', 'email.smtp_username', 'email.smtp_password', 'email.from_address', 'email.from_name', 'email.reply_to', 'audit.enabled', 'audit.categories', 'audit.screen_control_commands', 'audit.include_request_metadata', 'audit.retention_days']);
await pool.query('DELETE FROM o_app_settings WHERE setting_key NOT IN (' + ALL_SETTING_KEY_PLACEHOLDERS + ')', ALL_SETTING_KEYS);
const savedSettings = await saveAppSettings(pool, {
'uploads.image_max_bytes': imageMaxMb * 1024 * 1024,
'uploads.video_max_bytes': videoMaxMb * 1024 * 1024,
@@ -533,7 +539,7 @@ module.exports = function registerSettingsPageRoutes(app, deps) {
error.expose = true;
throw error;
}
await pool.query('DELETE FROM o_app_settings WHERE setting_key NOT IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', ['announcements.suggested_icons', 'announcements.default_icon', 'announcements.default_duration_value', 'announcements.default_duration_unit', 'player.default_slide_duration_seconds', 'player.default_fade_between_slides', 'player.skip_unavailable_rtmp', 'data-sources.rss_default_interval_value', 'data-sources.rss_default_interval_unit', 'data-sources.api_default_interval_value', 'data-sources.api_default_interval_unit', 'weather.open_meteo_api_key', 'weather.pirate_weather_api_key', 'uploads.image_max_bytes', 'uploads.video_max_bytes', 'uploads.wysiwyg_image_max_bytes', 'uploads.allowed_mime_types', 'security.session_lifetime_days', 'security.allow_user_session_revocation', 'security.max_active_sessions', 'security.login_max_attempts', 'security.login_lockout_minutes', 'security.login_rate_limit_scope', 'security.password_min_length', 'security.password_min_categories', 'security.password_require_lowercase', 'security.password_require_uppercase', 'security.password_require_number', 'security.password_require_symbol', 'security.require_password_change_for_new_users', 'security.require_password_change_after_admin_reset', 'audit.enabled', 'audit.categories', 'audit.screen_control_commands', 'audit.include_request_metadata', 'audit.retention_days']);
await pool.query('DELETE FROM o_app_settings WHERE setting_key NOT IN (' + ALL_SETTING_KEY_PLACEHOLDERS + ')', ALL_SETTING_KEYS);
const savedSettings = await saveAppSettings(pool, {
'announcements.suggested_icons': suggestedIcons
}, req.currentUser && req.currentUser.id);
+6
View File
@@ -66,6 +66,12 @@ test('settings route renders the overview', async () => {
});
assert.ok(queries.some(function (entry) { return entry.sql && /DELETE FROM o_app_settings/.test(entry.sql); }));
assert.ok(queries.some(function (entry) { return entry.sql && /INSERT INTO o_app_settings/.test(entry.sql); }));
queries.filter(function (entry) {
return entry.sql && /DELETE FROM o_app_settings/.test(entry.sql);
}).forEach(function (entry) {
assert.equal((entry.sql.match(/\?/g) || []).length, entry.params.length);
assert.ok(entry.params.includes('email.invitation_body'));
});
assert.match(saveResponse.redirectedTo, /^\/settings\/system\?message=/);
let tooManyError = null;