diff --git a/src/mailer.js b/src/mailer.js index 351220f2a..77555d10f 100644 --- a/src/mailer.js +++ b/src/mailer.js @@ -108,31 +108,29 @@ function sendInvite(user, invitor, inviteLink) { debug('Sending invite mail'); - getMailConfig(function (error, mailConfig) { + getMailConfig(async function (error, mailConfig) { if (error) return debug('Error getting mail details:', error); - translation.getTranslations(function (error, translationAssets) { - if (error) return debug('Error getting translations:', error); + const translationAssets = await translation.getTranslations(); - var templateData = { - user: user.displayName || user.username || user.email, - webadminUrl: settings.dashboardOrigin(), - inviteLink: inviteLink, - invitor: invitor ? invitor.email : null, - cloudronName: mailConfig.cloudronName, - cloudronAvatarUrl: settings.dashboardOrigin() + '/api/v1/cloudron/avatar' - }; + const templateData = { + user: user.displayName || user.username || user.email, + webadminUrl: settings.dashboardOrigin(), + inviteLink: inviteLink, + invitor: invitor ? invitor.email : null, + cloudronName: mailConfig.cloudronName, + cloudronAvatarUrl: settings.dashboardOrigin() + '/api/v1/cloudron/avatar' + }; - var mailOptions = { - from: mailConfig.notificationFrom, - to: user.fallbackEmail, - subject: ejs.render(translation.translate('{{ welcomeEmail.subject }}', translationAssets.translations || {}, translationAssets.fallback || {}), { cloudron: mailConfig.cloudronName }), - text: render('welcome_user-text.ejs', templateData, translationAssets), - html: render('welcome_user-html.ejs', templateData, translationAssets) - }; + const mailOptions = { + from: mailConfig.notificationFrom, + to: user.fallbackEmail, + subject: ejs.render(translation.translate('{{ welcomeEmail.subject }}', translationAssets.translations || {}, translationAssets.fallback || {}), { cloudron: mailConfig.cloudronName }), + text: render('welcome_user-text.ejs', templateData, translationAssets), + html: render('welcome_user-html.ejs', templateData, translationAssets) + }; - sendMail(mailOptions); - }); + sendMail(mailOptions); }); } @@ -149,32 +147,30 @@ function sendNewLoginLocation(user, loginLocation) { debug('Sending new login location mail'); - getMailConfig(function (error, mailConfig) { + getMailConfig(async function (error, mailConfig) { if (error) return debug('Error getting mail details:', error); - translation.getTranslations(function (error, translationAssets) { - if (error) return debug('Error getting translations:', error); + const translationAssets = await translation.getTranslations(); - const templateData = { - user: user.displayName || user.username || user.email, - ip, - userAgent: userAgent || 'unknown', - country, - city, - cloudronName: mailConfig.cloudronName, - cloudronAvatarUrl: settings.dashboardOrigin() + '/api/v1/cloudron/avatar' - }; + const templateData = { + user: user.displayName || user.username || user.email, + ip, + userAgent: userAgent || 'unknown', + country, + city, + cloudronName: mailConfig.cloudronName, + cloudronAvatarUrl: settings.dashboardOrigin() + '/api/v1/cloudron/avatar' + }; - const mailOptions = { - from: mailConfig.notificationFrom, - to: user.fallbackEmail, - subject: ejs.render(translation.translate('{{ newLoginEmail.subject }}', translationAssets.translations || {}, translationAssets.fallback || {}), { cloudron: mailConfig.cloudronName }), - text: render('new_login_location-text.ejs', templateData, translationAssets), - html: render('new_login_location-html.ejs', templateData, translationAssets) - }; + const mailOptions = { + from: mailConfig.notificationFrom, + to: user.fallbackEmail, + subject: ejs.render(translation.translate('{{ newLoginEmail.subject }}', translationAssets.translations || {}, translationAssets.fallback || {}), { cloudron: mailConfig.cloudronName }), + text: render('new_login_location-text.ejs', templateData, translationAssets), + html: render('new_login_location-html.ejs', templateData, translationAssets) + }; - sendMail(mailOptions); - }); + sendMail(mailOptions); }); } @@ -183,29 +179,27 @@ function passwordReset(user) { debug('Sending mail for password reset for user %s.', user.email, user.id); - getMailConfig(function (error, mailConfig) { + getMailConfig(async function (error, mailConfig) { if (error) return debug('Error getting mail details:', error); - translation.getTranslations(function (error, translationAssets) { - if (error) return debug('Error getting translations:', error); + const translationAssets = await translation.getTranslations(); - var templateData = { - user: user.displayName || user.username || user.email, - resetLink: `${settings.dashboardOrigin()}/login.html?resetToken=${user.resetToken}`, - cloudronName: mailConfig.cloudronName, - cloudronAvatarUrl: settings.dashboardOrigin() + '/api/v1/cloudron/avatar' - }; + const templateData = { + user: user.displayName || user.username || user.email, + resetLink: `${settings.dashboardOrigin()}/login.html?resetToken=${user.resetToken}`, + cloudronName: mailConfig.cloudronName, + cloudronAvatarUrl: settings.dashboardOrigin() + '/api/v1/cloudron/avatar' + }; - var mailOptions = { - from: mailConfig.notificationFrom, - to: user.fallbackEmail, - subject: ejs.render(translation.translate('{{ passwordResetEmail.subject }}', translationAssets.translations || {}, translationAssets.fallback || {}), { cloudron: mailConfig.cloudronName }), - text: render('password_reset-text.ejs', templateData, translationAssets), - html: render('password_reset-html.ejs', templateData, translationAssets) - }; + const mailOptions = { + from: mailConfig.notificationFrom, + to: user.fallbackEmail, + subject: ejs.render(translation.translate('{{ passwordResetEmail.subject }}', translationAssets.translations || {}, translationAssets.fallback || {}), { cloudron: mailConfig.cloudronName }), + text: render('password_reset-text.ejs', templateData, translationAssets), + html: render('password_reset-html.ejs', templateData, translationAssets) + }; - sendMail(mailOptions); - }); + sendMail(mailOptions); }); } diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index b575f5b69..ade446c14 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -311,12 +311,11 @@ function getServerIp(req, res, next) { }); } -function getLanguages(req, res, next) { - translation.getLanguages(function (error, languages) { - if (error) return next(new BoxError.toHttpError(error)); +async function getLanguages(req, res, next) { + const [error, languages] = await safe(translation.getLanguages()); + if (error) return next(new BoxError.toHttpError(error)); - next(new HttpSuccess(200, { languages })); - }); + next(new HttpSuccess(200, { languages })); } async function syncDnsRecords(req, res, next) { diff --git a/src/routes/settings.js b/src/routes/settings.js index d958f96f9..ee17c70c2 100644 --- a/src/routes/settings.js +++ b/src/routes/settings.js @@ -248,24 +248,22 @@ function setSysinfoConfig(req, res, next) { }); } -function getLanguage(req, res, next) { - settings.getLanguage(function (error, language) { - if (error) return next(BoxError.toHttpError(error)); +async function getLanguage(req, res, next) { + const [error, language] = await safe(settings.getLanguage()); + if (error) return next(BoxError.toHttpError(error)); - next(new HttpSuccess(200, { language })); - }); + next(new HttpSuccess(200, { language })); } -function setLanguage(req, res, next) { +async function setLanguage(req, res, next) { assert.strictEqual(typeof req.body, 'object'); if (!req.body.language || typeof req.body.language !== 'string') return next(new HttpError(400, 'language is required')); - settings.setLanguage(req.body.language, function (error) { - if (error) return next(BoxError.toHttpError(error)); + const [error] = await safe(settings.setLanguage(req.body.language)); + if (error) return next(BoxError.toHttpError(error)); - next(new HttpSuccess(200, {})); - }); + next(new HttpSuccess(200, {})); } function get(req, res, next) { diff --git a/src/settings.js b/src/settings.js index 9b5292623..fb9f55b67 100644 --- a/src/settings.js +++ b/src/settings.js @@ -698,34 +698,21 @@ async function setLicenseKey(licenseKey) { notifyChange(exports.LICENSE_KEY, licenseKey); } -function getLanguage(callback) { - assert.strictEqual(typeof callback, 'function'); - - settingsdb.get(exports.LANGUAGE_KEY, function (error, value) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.LANGUAGE_KEY]); - if (error) return callback(error); - - callback(null, value); - }); +async function getLanguage() { + const value = await get(exports.LANGUAGE_KEY); + if (value === null) return gDefaults[exports.LANGUAGE_KEY]; + return value; } -function setLanguage(language, callback) { +async function setLanguage(language) { assert.strictEqual(typeof language, 'string'); - assert.strictEqual(typeof callback, 'function'); - translation.getLanguages(function (error, languages) { - if (error) return callback(error); + const languages = await translation.getLanguages(); - if (languages.indexOf(language) === -1) return callback(new BoxError(BoxError.NOT_FOUND)); + if (languages.indexOf(language) === -1) throw new BoxError(BoxError.NOT_FOUND, 'Language not found'); - settingsdb.set(exports.LANGUAGE_KEY, language, function (error) { - if (error) return callback(error); - - notifyChange(exports.LANGUAGE_KEY, language); - - callback(null); - }); - }); + await set(exports.LANGUAGE_KEY, language); + notifyChange(exports.LANGUAGE_KEY, language); } async function getCloudronId() { diff --git a/src/translation.js b/src/translation.js index 21b4fb7b4..cdbf74463 100644 --- a/src/translation.js +++ b/src/translation.js @@ -6,11 +6,12 @@ exports = module.exports = { getLanguages }; -var assert = require('assert'), +const assert = require('assert'), debug = require('debug')('box:translation'), fs = require('fs'), path = require('path'), paths = require('./paths.js'), + safe = require('safetydance'), settings = require('./settings.js'); const TRANSLATION_FOLDER = path.join(paths.DASHBOARD_DIR, 'translation'); @@ -21,13 +22,13 @@ function translate(input, translations, fallbackTranslations) { assert.strictEqual(typeof translations, 'object'); assert.strictEqual(typeof fallbackTranslations, 'object'); - var tokens = input.match(/{{(.*?)}}/gm); + const tokens = input.match(/{{(.*?)}}/gm); if (!tokens) return input; - var output = input; + let output = input; tokens.forEach(function (token) { - var key = token.slice(2).slice(0, -2).trim(); - var value = key.split('.').reduce(function (acc, cur) { + const key = token.slice(2).slice(0, -2).trim(); + let value = key.split('.').reduce(function (acc, cur) { if (acc === null) return null; return typeof acc[cur] !== 'undefined' ? acc[cur] : null; }, translations); @@ -46,45 +47,36 @@ function translate(input, translations, fallbackTranslations) { return output; } -function getTranslations(callback) { - assert.strictEqual(typeof callback, 'function'); - - var fallback = {}; - try { - fallback = JSON.parse(fs.readFileSync(path.join(TRANSLATION_FOLDER, 'en.json'), 'utf8')); - } catch (e) { - debug('getTranslations: Fallback language en not found', e); +async function getTranslations() { + let fallback = safe.JSON.parse(fs.readFileSync(path.join(TRANSLATION_FOLDER, 'en.json'), 'utf8')); + if (!fallback) { + debug('getTranslations: Fallback language en not found', safe.error); + fallback = {}; } - settings.getLanguage(function (error, lang) { - if (error) return callback(error); + const lang = await settings.getLanguage(); - var translations = {}; - try { - translations = JSON.parse(fs.readFileSync(path.join(TRANSLATION_FOLDER, lang + '.json'), 'utf8')); - } catch (e) { - debug(`getTranslations: Requested language ${lang} not found`, e); - } + let translations = safe.JSON.parse(fs.readFileSync(path.join(TRANSLATION_FOLDER, lang + '.json'), 'utf8')); + if (!translations) { + debug(`getTranslations: Requested language ${lang} not found`, safe.error); + translations = {}; + } - return callback(null, { translations, fallback }); - }); + return { translations, fallback }; } -function getLanguages(callback) { - assert.strictEqual(typeof callback, 'function'); - +async function getLanguages() { // we always return english to avoid dashboard breakage - var languages = ['en']; + let languages = ['en']; - fs.readdir(TRANSLATION_FOLDER, function (error, result) { - if (error) { - debug('getLanguages: Failed to list translations', error); - return callback(null, languages); - } + const [error, result] = await safe(fs.promises.readdir(TRANSLATION_FOLDER)); + if (error) { + debug('getLanguages: Failed to list translations', error); + return languages; + } - var jsonFiles = result.filter(function (file) { return path.extname(file) === '.json'; }); - languages = jsonFiles.map(function (file) { return path.basename(file, '.json'); }); + const jsonFiles = result.filter(function (file) { return path.extname(file) === '.json'; }); + languages = jsonFiles.map(function (file) { return path.basename(file, '.json'); }); - callback(null, languages); - }); + return languages; }