diff --git a/js/config.js b/js/config.js index f8eef332..ba92566f 100644 --- a/js/config.js +++ b/js/config.js @@ -4,15 +4,16 @@ const electron = require('electron'); const app = electron.app; const path = require('path'); const fs = require('fs'); +const AppDirectory = require('appdirectory'); +const omit = require('lodash.omit'); + const isDevEnv = require('./utils/misc.js').isDevEnv; const isMac = require('./utils/misc.js').isMac; const getRegistry = require('./utils/getRegistry.js'); -const configFileName = 'Symphony.config'; +const log = require('./log.js'); +const logLevels = require('./enums/logLevels.js'); -// For modifying user config while installation -const pick = require('lodash.pick'); -const childProcess = require('child_process'); -const AppDirectory = require('appdirectory'); +const configFileName = 'Symphony.config'; const dirs = new AppDirectory('Symphony'); // cached config when first reading files. initially undefined and will be @@ -20,6 +21,8 @@ const dirs = new AppDirectory('Symphony'); let userConfig; let globalConfig; +let ignoreSettings = ['minimizeOnClose', 'launchOnStartup', 'alwaysOnTop', 'url']; + /** * Tries to read given field from user config file, if field doesn't exist * then tries reading from global config. User config is stord in directory: @@ -35,10 +38,10 @@ let globalConfig; */ function getConfigField(fieldName) { return getUserConfigField(fieldName) - .then(function(value) { + .then((value) => { // got value from user config return value; - }, function() { + }, () => { // failed to get value from user config, so try global config return getGlobalConfigField(fieldName); }); @@ -50,7 +53,7 @@ function getConfigField(fieldName) { * @returns {Promise} */ function getUserConfigField(fieldName) { - return readUserConfig().then(function(config) { + return readUserConfig().then((config) => { if (typeof fieldName === 'string' && fieldName in config) { return config[fieldName]; } @@ -65,7 +68,7 @@ function getUserConfigField(fieldName) { * @returns {Promise} */ function readUserConfig(customConfigPath) { - return new Promise(function(resolve, reject) { + return new Promise((resolve, reject) => { if (userConfig) { resolve(userConfig); return; @@ -77,7 +80,7 @@ function readUserConfig(customConfigPath) { configPath = path.join(app.getPath('userData'), configFileName); } - fs.readFile(configPath, 'utf8', function(err, data) { + fs.readFile(configPath, 'utf8', (err, data) => { if (err) { reject('cannot open user config file: ' + configPath + ', error: ' + err); } else { @@ -100,7 +103,7 @@ function readUserConfig(customConfigPath) { * @returns {Promise} */ function getGlobalConfigField(fieldName) { - return readGlobalConfig().then(function(config) { + return readGlobalConfig().then((config) => { if (typeof fieldName === 'string' && fieldName in config) { return config[fieldName]; } @@ -118,7 +121,7 @@ function getGlobalConfigField(fieldName) { * installed app). for dev env, the file is read directly from packed asar file. */ function readGlobalConfig() { - return new Promise(function(resolve, reject) { + return new Promise((resolve, reject) => { if (globalConfig) { resolve(globalConfig); return; @@ -138,7 +141,7 @@ function readGlobalConfig() { configPath = path.join(execPath, isMac ? '..' : '', globalConfigFileName); } - fs.readFile(configPath, 'utf8', function(err, data) { + fs.readFile(configPath, 'utf8', (err, data) => { if (err) { reject('cannot open global config file: ' + configPath + ', error: ' + err); } else { @@ -149,10 +152,10 @@ function readGlobalConfig() { reject('can not parse config file data: ' + data + ', error: ' + err); } getRegistry('PodUrl') - .then(function(url) { + .then((url) => { globalConfig.url = url; resolve(globalConfig); - }).catch(function() { + }).catch(() => { resolve(globalConfig); }); } @@ -168,9 +171,9 @@ function readGlobalConfig() { */ function updateConfigField(fieldName, newValue) { return readUserConfig() - .then(function(config) { + .then((config) => { return saveUserConfig(fieldName, newValue, config); - }, function() { + }, () => { // in case config doesn't exist, can't read or is corrupted. // add configVersion - just in case in future we need to provide // upgrade capabilities. @@ -188,7 +191,7 @@ function updateConfigField(fieldName, newValue) { * @returns {Promise} */ function saveUserConfig(fieldName, newValue, oldConfig) { - return new Promise(function(resolve, reject) { + return new Promise((resolve, reject) => { let configPath = path.join(app.getPath('userData'), configFileName); if (!oldConfig || !fieldName) { @@ -214,129 +217,100 @@ function saveUserConfig(fieldName, newValue, oldConfig) { } /** - * Method to update multiple user config field - * @param {Object} newGlobalConfig - The latest config changes from installer - * @param {Object} oldUserConfig - The old user config data - * @returns {Promise} + * Updates the existing user config settings by removing + * 'minimizeOnClose', 'launchOnStartup', 'url' and 'alwaysOnTop' + * @param {Object} oldUserConfig the old user config object */ -function updateUserConfig(newGlobalConfig, oldUserConfig) { - return new Promise((resolve, reject) => { - // Picking some values from global config to overwrite user config - const configDataToUpdate = pick(newGlobalConfig, ['url', 'minimizeOnClose', 'launchOnStartup', 'alwaysOnTop']); - const updatedUserConfigData = Object.assign(oldUserConfig, configDataToUpdate); - const jsonNewConfig = JSON.stringify(updatedUserConfigData, null, ' '); - // get user config path - let userConfigFile; +function updateUserConfig(oldUserConfig) { + return new Promise((resolve, reject) => { + + // create a new object from the old user config + // by ommitting the user related settings from + // the old user config + let newUserConfig = omit(oldUserConfig, ignoreSettings); + let newUserConfigString = JSON.stringify(newUserConfig, null, 2); + + // get the user config path + let userConfigFile; if (isMac) { userConfigFile = path.join(dirs.userConfig(), configFileName); } else { userConfigFile = path.join(app.getPath('userData'), configFileName); } - fs.writeFile(userConfigFile, jsonNewConfig, 'utf8', (err) => { - if (err) { - reject(err); - return; - } - resolve(); - }); + if (!userConfigFile) { + return reject('user config file doesn\'t exist'); + } + + // write the new user config changes to the user config file + fs.writeFileSync(userConfigFile, newUserConfigString, 'utf-8'); + + return resolve(); + }); + } /** - * Method to overwrite user config on windows installer - * @param {String} perUserInstall - Is a flag to determine whether we are installing for per user + * Manipulates user config on windows + * @param {String} perUserInstall - Is a flag to determine if we are installing for an individual user * @returns {Promise} */ function updateUserConfigWin(perUserInstall) { + return new Promise((resolve, reject) => { + + // we get the user config path using electron const userConfigFile = path.join(app.getPath('userData'), configFileName); - // flag to determine whether per user installation - if (!perUserInstall) { + + // if it's not a per user installation or if the + // user config file doesn't exist, we simple move on + if (!perUserInstall || !fs.existsSync(userConfigFile)) { + log.send(logLevels.WARN, 'config: Could not find the user config file!'); reject(); return; } - // if user config file does't exists just copy global config file - if (!fs.existsSync(userConfigFile)) { - resolve(copyConfigWin()); - return; - } + // In case the file exists, we remove it so that all the + // values are fetched from the global config + // https://perzoinc.atlassian.net/browse/ELECTRON-126 + readUserConfig(userConfigFile).then((data) => { + resolve(updateUserConfig(data)); + }).catch((err) => { + reject(err); + }); - Promise.all([readGlobalConfig(), readUserConfig(userConfigFile)]) - .then((data) => { - resolve(updateUserConfig(data[0], data[1])); - }) - .catch((err) => { - reject(err); - }); }); + } /** - * Method to overwrite user config on mac installer + * Manipulates user config on macOS * @param {String} globalConfigPath - The global config path from installer * @returns {Promise} */ -function updateUserConfigMac(globalConfigPath) { +function updateUserConfigMac() { return new Promise((resolve, reject) => { const userConfigFile = path.join(dirs.userConfig(), configFileName); - // if user config file does't exists just copy global config file + // if user config file does't exist, just use the global config settings + // i.e. until an user makes changes manually using the menu items if (!fs.existsSync(userConfigFile)) { - resolve(copyConfigMac(globalConfigPath)); + log.send(logLevels.WARN, 'config: Could not find the user config file!'); + reject(); return; } - Promise.all([readGlobalConfig(), readUserConfig(userConfigFile)]) - .then((data) => { - resolve(updateUserConfig(data[0], data[1])); - }) - .catch((err) => { - reject(err); - }); - }); -} - -/** - * Method to copy global config file to user config directory for Windows - * @returns {Promise} - */ -function copyConfigWin() { - return new Promise((resolve, reject) => { - const globalConfigFileName = path.join('config', configFileName); - const execPath = path.dirname(app.getPath('exe')); - const globalConfigPath = path.join(execPath, '', globalConfigFileName); - const userConfigPath = app.getPath('userData'); - - childProcess.exec(`echo D|xcopy /y /e /s /c "${globalConfigPath}" "${userConfigPath}"`, { timeout: 60000 }, (err) => { - if (err) { - reject(err); - return; - } - resolve(); - }); - }); -} - -/** - * Method which copies global config file to user config directory for mac - * @param {String} globalConfigPath - The global config path from installer - * @returns {Promise} - */ -function copyConfigMac(globalConfigPath) { - return new Promise((resolve, reject) => { - let userConfigPath = dirs.userConfig() + '/'; - let userName = process.env.USER; - - childProcess.exec(`rsync -r "${globalConfigPath}" "${userConfigPath}" && chown -R "${userName}" "${userConfigPath}"`, { timeout: 60000 }, (err) => { - if (err) { - reject(err); - return; - } - resolve(); + // In case the file exists, we remove it so that all the + // values are fetched from the global config + // https://perzoinc.atlassian.net/browse/ELECTRON-126 + readUserConfig(userConfigFile).then((data) => { + resolve(updateUserConfig(data)); + }).catch((err) => { + reject(err); }); + }); } @@ -349,13 +323,17 @@ function clearCachedConfigs() { } module.exports = { - getConfigField, - updateConfigField, + configFileName, + + getConfigField, + + updateConfigField, updateUserConfigWin, updateUserConfigMac, // items below here are only exported for testing, do NOT use! saveUserConfig, clearCachedConfigs -}; \ No newline at end of file + +}; diff --git a/js/main.js b/js/main.js index 6a8d3111..489d6bfe 100644 --- a/js/main.js +++ b/js/main.js @@ -8,13 +8,8 @@ const squirrelStartup = require('electron-squirrel-startup'); const AutoLaunch = require('auto-launch'); const urlParser = require('url'); -const childProcess = require('child_process'); -const path = require('path'); -const AppDirectory = require('appdirectory'); -const dirs = new AppDirectory('Symphony'); - // Local Dependencies -const { getConfigField } = require('./config.js'); +const {getConfigField, updateUserConfigWin, updateUserConfigMac} = require('./config.js'); const { isMac, isDevEnv } = require('./utils/misc.js'); const protocolHandler = require('./protocolHandler'); const getCmdLineArg = require('./utils/getCmdLineArg.js'); @@ -122,8 +117,7 @@ function setupThenOpenMainWindow() { isAppAlreadyOpen = true; - // allows installer to launch app and set auto startup mode then - // immediately quit. + // allows installer to launch app and set appropriate global / user config params. let hasInstallFlag = getCmdLineArg(process.argv, '--install', true); let perUserInstall = getCmdLineArg(process.argv, '--peruser', true); if (!isMac && hasInstallFlag) { @@ -178,43 +172,6 @@ function setStartup(lStartup) { }); } -/** - * Method to overwrite user config on mac installer - * @returns {Promise} - */ -function updateUserConfigMac() { - return new Promise((resolve, reject) => { - let userConfigPath = dirs.userConfig() + '/'; - let globalConfigPath = process.argv[2]; - let userName = process.env.USER; - - childProcess.exec(`rsync -r "${globalConfigPath}" "${userConfigPath}" && chown -R "${userName}" "${userConfigPath}"`, {timeout: 60000}, (err) => { - if (err) { - reject(err); - } - resolve(); - }); - }); -} - -/** - * Method to overwrite user config on windows installer - * @returns {Promise} - */ -function updateUserConfigWin() { - return new Promise((resolve, reject) => { - let userConfigPath = app.getPath('userData'); - let globalConfigPath = path.join(__dirname, '..', '..', '..', 'config/Symphony.config'); - - childProcess.exec(`echo D|xcopy /y /e /s /c "${globalConfigPath}" "${userConfigPath}"`, {timeout: 60000}, (err) => { - if (err) { - reject(err); - } - resolve(); - }); - }); -} - /** * Checks for the url argument, processes it * and creates the main window diff --git a/js/preload/preloadMain.js b/js/preload/preloadMain.js index dd9c9d18..fdc6b0cc 100644 --- a/js/preload/preloadMain.js +++ b/js/preload/preloadMain.js @@ -40,8 +40,6 @@ document.addEventListener('DOMContentLoaded', () => { } }); -const nodeURL = require('url'); - // hold ref so doesn't get GC'ed const local = { ipcRenderer: ipcRenderer diff --git a/package-lock.json b/package-lock.json index 0ff5a8d7..21fa6d50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2392,6 +2392,11 @@ } } }, + "electron-log": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-2.2.9.tgz", + "integrity": "sha512-WNMSipQYurNxY14RO6IKgcxcZg1e4aNVpUUJK9q7Bqe0TZEKn1e5h4HiQKhTgVLqKrUn++ugOZrty450P9vpjA==" + }, "electron-macos-sign": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/electron-macos-sign/-/electron-macos-sign-1.6.0.tgz", @@ -5147,6 +5152,11 @@ "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", "dev": true }, + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=" + }, "lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", diff --git a/package.json b/package.json index b9570620..c7d89f7e 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "electron-squirrel-startup": "^1.0.0", "filesize": "^3.5.10", "keymirror": "0.1.1", - "lodash.pick": "^4.4.0", + "lodash.omit": "^4.5.0", "winreg": "^1.2.3" }, "optionalDependencies": {