const SERVICE_NAME = "SettingsService"; const envConfig = { logLevel: undefined, apiBaseUrl: undefined, clientHost: process.env.CLIENT_HOST, jwtSecret: process.env.JWT_SECRET, refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET, dbType: process.env.DB_TYPE, dbConnectionString: process.env.DB_CONNECTION_STRING, redisHost: process.env.REDIS_HOST, redisPort: process.env.REDIS_PORT, jwtTTL: process.env.TOKEN_TTL, refreshTokenTTL: process.env.REFRESH_TOKEN_TTL, pagespeedApiKey: process.env.PAGESPEED_API_KEY, systemEmailHost: process.env.SYSTEM_EMAIL_HOST, systemEmailPort: process.env.SYSTEM_EMAIL_PORT, systemEmailAddress: process.env.SYSTEM_EMAIL_ADDRESS, systemEmailPassword: process.env.SYSTEM_EMAIL_PASSWORD, }; /** * SettingsService * * This service is responsible for loading and managing the application settings. * It gives priority to environment variables and will only load settings * from the database if they are not set in the environment. */ class SettingsService { /** * Constructs a new SettingsService * @constructor * @throws {Error} */ constructor(appSettings) { this.appSettings = appSettings; this.settings = { ...envConfig }; } /** * Load settings from the database and merge with environment settings. * If there are any settings that weren't set by environment variables, use user settings from the database. * @returns {Promise} The merged settings. * @throws Will throw an error if settings are not found in the database or if settings have not been loaded. */ async loadSettings() { try { const dbSettings = await this.appSettings.findOne(); if (!this.settings) { throw new Error("Settings not found"); } // If there are any settings that weren't set by environment variables, use user settings from DB for (const key in envConfig) { if (envConfig[key] === undefined && dbSettings[key] !== undefined) { this.settings[key] = dbSettings[key]; } } return this.settings; } catch (error) { error.service === undefined ? (error.service = SERVICE_NAME) : null; error.method === undefined ? (error.method = "loadSettings") : null; throw error; } } /** * Reload settings by calling loadSettings. * @returns {Promise} The reloaded settings. */ async reloadSettings() { return this.loadSettings(); } /** * Get the current settings. * @returns {Object} The current settings. * @throws Will throw an error if settings have not been loaded. */ getSettings() { if (!this.settings) { throw new Error("Settings have not been loaded"); } return this.settings; } } export default SettingsService;