From d894f185e948725d6da76202dca5b0c61697fc25 Mon Sep 17 00:00:00 2001 From: dbauszus-glx Date: Thu, 2 Nov 2023 19:35:18 +0000 Subject: [PATCH] getLocale; role checks; remove clone; logout msg; xhr resolution; --- api/api.js | 2 +- lib/utils/xhr.mjs | 39 +++--- mod/location/_location.js | 33 ++--- mod/location/get.js | 4 +- mod/mvt.js | 2 +- mod/query.js | 15 +-- mod/user/_user.js | 3 +- mod/utils/clone.js | 24 ---- mod/view.js | 27 ---- mod/workspace/_workspace.js | 26 ++-- mod/workspace/cache.js | 23 +--- mod/workspace/getLayer.js | 21 ++- mod/workspace/getLocale.js | 33 +++++ mod/workspace/templates/msgs.js | 231 ++++++++++++++++---------------- public/views/_default.js | 17 ++- 15 files changed, 242 insertions(+), 258 deletions(-) delete mode 100644 mod/utils/clone.js create mode 100644 mod/workspace/getLocale.js diff --git a/api/api.js b/api/api.js index 4b55fda9b..5787ffbc6 100644 --- a/api/api.js +++ b/api/api.js @@ -130,7 +130,7 @@ module.exports = async (req, res) => { res.setHeader('Set-Cookie', `${process.env.TITLE}=null;HttpOnly;Max-Age=0;Path=${process.env.DIR || '/'}`) // Remove logout parameter. - res.setHeader('location', `${process.env.DIR || '/'}`) + res.setHeader('location', (process.env.DIR || '/') + (req.params.msg && `?msg=${req.params.msg}`||'')) return res.status(302).send() } diff --git a/lib/utils/xhr.mjs b/lib/utils/xhr.mjs index 1a59cd601..7a66eb0d7 100644 --- a/lib/utils/xhr.mjs +++ b/lib/utils/xhr.mjs @@ -1,28 +1,42 @@ const requestMap = new Map() -export default params => new Promise((resolve, reject) => { +export default params => new Promise(resolve => { - if (!params) return reject() + // Return if params are falsy. + if (!params) { + console.error(`xhr params are falsy.`) + return; + } + // Set params as object with url from string. params = typeof params === 'string' ? { url: params } : params + // A request url must be provided. + if (!params.url) { + console.error(`no xhr request url has been provided.`) + return; + }; + // Check whether a request with the same params has already been resolved. if (params.cache && requestMap.has(params)) return resolve(requestMap.get(params)) + // Assign 'GET' as default method. + params.method ??= 'GET' + const xhr = new XMLHttpRequest() - xhr.open(params.method || 'GET', params.url) + xhr.open(params.method, params.url) // Use requestHeader: null to prevent assignment of requestHeader. if (params.requestHeader !== null) { + // Butter (spread) over requestHeader. const requestHeader = { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + ...params.requestHeader } - - Object.assign(requestHeader, params.requestHeader || {}) - - Object.entries(requestHeader).forEach(entry=>xhr.setRequestHeader(...entry)) + + Object.entries(requestHeader).forEach(entry => xhr.setRequestHeader(...entry)) } xhr.responseType = params.responseType || 'json' @@ -30,7 +44,7 @@ export default params => new Promise((resolve, reject) => { xhr.onload = e => { if (e.target.status >= 400) { - reject(new Error(e.target.status)) + resolve(new Error(e.target.status)) return; } @@ -38,14 +52,7 @@ export default params => new Promise((resolve, reject) => { params.cache && requestMap.set(params, e.target.response) resolve(params.resolveTarget ? e.target : e.target.response) - } - // xhr.onerror = err => { - // console.error(err) - // reject(err); - // }; - xhr.send(params.body) - }) \ No newline at end of file diff --git a/mod/location/_location.js b/mod/location/_location.js index e7203b18f..6c9c4a031 100644 --- a/mod/location/_location.js +++ b/mod/location/_location.js @@ -5,34 +5,27 @@ const methods = { delete: require('./delete'), } -const workspaceCache = require('../workspace/cache') +const Roles = require('../utils/roles') -module.exports = async (req, res) => { +const getLayer = require('../workspace/getLayer') - const workspace = await workspaceCache() +module.exports = async (req, res) => { if (!Object.hasOwn(methods, req.params.method)) { - return res.send(`Failed to evaluate 'method' param.

- Location API`) + return res.send(`Failed to evaluate 'method' param.`) } - const method = methods[req.params.method] - - if (typeof method !== 'function') return; - - const locale = req.params.locale && workspace.locales[req.params.locale] - - const layer = locale?.layers[req.params.layer] || workspace.templates[req.params.layer] + const layer = await getLayer(req.params) - if (!layer) return res.status(400).send('Layer not found.') - - req.params.layer = layer + if (layer instanceof Error) { + return res.status(400).send('Failed to access layer.') + } - if (!req.params.layer) { - return res.status(400).send(`Failed to evaluate 'layer' param.

- Location API`) + if (!Roles.check(layer, req.params.user?.roles)) { + return res.status(403).send('Role access denied for layer.') } - return method(req, res) - + req.params.layer = layer + + return methods[req.params.method](req, res) } diff --git a/mod/location/get.js b/mod/location/get.js index fce4aa17c..3d406c519 100644 --- a/mod/location/get.js +++ b/mod/location/get.js @@ -1,8 +1,8 @@ const dbs = require('../utils/dbs')() -const sqlFilter = require('../utils/sqlFilter.js') +const sqlFilter = require('../utils/sqlFilter') -const Roles = require('../utils/roles.js') +const Roles = require('../utils/roles') const workspaceCache = require('../workspace/cache') diff --git a/mod/mvt.js b/mod/mvt.js index 85e3c664d..f30897f1a 100644 --- a/mod/mvt.js +++ b/mod/mvt.js @@ -4,7 +4,7 @@ const sqlFilter = require('./utils/sqlFilter') const validateRequestParams = require('./utils/validateRequestParams') -const Roles = require('./utils/roles.js') +const Roles = require('./utils/roles') const logger = require('./utils/logger') diff --git a/mod/query.js b/mod/query.js index 84a6043a4..568e7f7fc 100644 --- a/mod/query.js +++ b/mod/query.js @@ -2,7 +2,7 @@ const dbs_connections = require('./utils/dbs')() const sqlFilter = require('./utils/sqlFilter') -const Roles = require('./utils/roles.js') +const Roles = require('./utils/roles') const logger = require('./utils/logger'); @@ -50,19 +50,12 @@ module.exports = async (req, res) => { // Assign role filter and viewport params from layer object. if (req.params.layer) { - // Get locale for layer. - const locale = workspace.locales[req.params.locale] - - // A layer must be found if the layer param is set. - if (!locale) return res.status(400).send('Locale not found.') - - if (!Object.hasOwn(locale.layers, req.params.layer)) { + const layer = await getLayer(req.params) - return res.status(400).send('Layer not found.') + if (layer instanceof Error) { + return res.status(400).send('Failed to access layer.') } - const layer = await getLayer(req.params) - if (!Roles.check(layer, req.params.user?.roles)) { return res.status(403).send('Role access denied for layer.') } diff --git a/mod/user/_user.js b/mod/user/_user.js index a01126f01..07db2d0af 100644 --- a/mod/user/_user.js +++ b/mod/user/_user.js @@ -50,8 +50,7 @@ module.exports = (req, res) => { const method = methods[req.params.method] if (!method) { - return res.send(`Failed to evaluate 'method' param.

- User API`) + return res.send(`Failed to evaluate 'method' param.`) } if (!req.params.user && (method.login || method.admin)) { diff --git a/mod/utils/clone.js b/mod/utils/clone.js deleted file mode 100644 index f3024b3bc..000000000 --- a/mod/utils/clone.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = function clone(target, map = new WeakMap()) { - - // Return the value if target is not an object or null - if (target === null - || typeof target !== 'object' - || typeof target === 'function') { - return target - } - - // Check whether target is an array. - let cloneTarget = Array.isArray(target) ? [] : {}; - - // Use WeakMap to prevent circular references. - if (map.get(target)) { - return map.get(target); - } - map.set(target, cloneTarget); - - for (const key in target) { - cloneTarget[key] = clone(target[key], map); - } - - return cloneTarget; -}; \ No newline at end of file diff --git a/mod/view.js b/mod/view.js index c4ab3ce9f..bd7a9797e 100644 --- a/mod/view.js +++ b/mod/view.js @@ -1,17 +1,9 @@ -const Roles = require('./utils/roles.js') - -const login = require('./user/login') - const logger = require('./utils/logger') const languageTemplates = require('./utils/languageTemplates') -const workspaceCache = require('./workspace/cache') - module.exports = async (req, res) => { - const workspace = await workspaceCache() - logger(req.url, 'view-req-url') const params = {} @@ -37,21 +29,6 @@ module.exports = async (req, res) => { params.language ??= req.params.user.language - const roles = req.params.user?.roles || [] - - const locales = Object.values(workspace.locales) - .filter(locale => !!Roles.check(locale, roles)) - .map(locale => ({ - key: locale.key, - name: locale.name - })) - - if (!locales.length) { - - req.params.msg = 'no_locales' - return login(req, res) - } - // Encode stringified user for template. params.user ??= encodeURI(JSON.stringify({ email: req.params.user.email, @@ -61,10 +38,6 @@ module.exports = async (req, res) => { })); } - // Object.entries(process.env) - // .filter(entry => entry[0].match(/^SRC_/)) - // .forEach(entry => params[entry[0].replace(/^SRC_/, '')]=entry[1]) - const template = await languageTemplates(params) const view = template.replace(/{{2}([A-Za-z][A-Za-z0-9]*)}{2}/g, matched => { diff --git a/mod/workspace/_workspace.js b/mod/workspace/_workspace.js index 32277073a..c93e4e199 100644 --- a/mod/workspace/_workspace.js +++ b/mod/workspace/_workspace.js @@ -1,10 +1,10 @@ -const clone = require('../utils/clone.js') +const Roles = require('../utils/roles') -const Roles = require('../utils/roles.js') +const workspaceCache = require('./cache') -const getLayer = require('./getLayer') +const getLocale = require('./getLocale') -const workspaceCache = require('./cache') +const getLayer = require('./getLayer') let workspace; @@ -69,21 +69,25 @@ function locales(req, res) { res.send(locales) } -function locale(req, res) { +async function locale(req, res) { if (req.params.locale && !Object.hasOwn(workspace.locales, req.params.locale)) { return res.status(400).send(`Unable to validate locale param.`) } - let locale = {}; + let locale; if (Object.hasOwn(workspace.locales, req.params.locale)) { - locale = clone(workspace.locales?.[req.params.locale]) + locale = await getLocale(req.params) } else if (typeof workspace.locale === 'object') { - locale = clone(workspace.locale) + locale = workspace.locale + } + + if (locale instanceof Error) { + return res.status(400).send('Failed to access locale.') } const roles = req.params.user?.roles || [] @@ -92,6 +96,12 @@ function locale(req, res) { return res.status(403).send('Role access denied.') } + // Subtitutes ${*} in locale with process.env.SRC_* values. + locale = JSON.parse( + JSON.stringify(locale).replace(/\$\{(.*?)\}/g, + matched => process.env[`SRC_${matched.replace(/\$|\{|\}/g, '')}`] || matched) + ) + // Check layer access. locale.layers = locale.layers && Object.entries(locale.layers) .filter(layer => !!Roles.check(layer[1], roles)) diff --git a/mod/workspace/cache.js b/mod/workspace/cache.js index c2befe7e1..e2dd8f98a 100644 --- a/mod/workspace/cache.js +++ b/mod/workspace/cache.js @@ -82,25 +82,14 @@ async function cacheWorkspace() { // Get locale object from key. const locale = workspace.locales[locale_key] - // A default locale has been defined in the workspace. - if (typeof workspace.locale === 'object') { - - // Merge the workspace template into workspace. - merge(locale, workspace.locale) - } - - // A template exists for the locale key. - if (Object.hasOwn(workspace.templates, locale_key) && typeof workspace.templates[locale_key] === 'object') { - - // Merge the workspace template into workspace. - merge(locale, workspace.templates[locale_key]) - } + // Merge the workspace template into workspace. + merge(locale, workspace.locale) // Assign key value as key on locale object. locale.key = locale_key // Assign locale key as name with no existing name on locale object. - locale.name = locale.name || locale_key + locale.name ??= locale_key }) if (workspace.plugins) { @@ -108,12 +97,6 @@ async function cacheWorkspace() { console.warn(`Default plugins should be defined in the default workspace.locale{}`) } - // Substitute all SRC_* variables in locales. - workspace.locales = JSON.parse( - JSON.stringify(workspace.locales).replace(/\$\{(.*?)\}/g, - matched => process.env[`SRC_${matched.replace(/\$|\{|\}/g, '')}`] || matched) - ) - timestamp = Date.now() cache = workspace diff --git a/mod/workspace/getLayer.js b/mod/workspace/getLayer.js index 575378c3f..8aa9675d9 100644 --- a/mod/workspace/getLayer.js +++ b/mod/workspace/getLayer.js @@ -1,29 +1,36 @@ -const Roles = require('../utils/roles.js') +const Roles = require('../utils/roles') const merge = require('../utils/merge') -const getTemplate = require('./getTemplate') - const workspaceCache = require('./cache') +const getLocale = require('./getLocale') + +const getTemplate = require('./getTemplate') + module.exports = async (params) => { const workspace = await workspaceCache() if (!Object.hasOwn(workspace.locales, params.locale)) { - return new Error('Unable to validate locale param.') //400 + return new Error('Unable to validate locale param.') } - const locale = workspace.locales[params.locale] + const locale = await getLocale(params) + + if (locale instanceof Error) { + + return locale + } const roles = params.user?.roles || [] if (!Roles.check(locale, roles)) { - return new Error('Role access denied.') //403 + return new Error('Role access denied.') } if (!Object.hasOwn(locale.layers, params.layer)) { - return new Error('Unable to validate layer param.') //400 + return new Error('Unable to validate layer param.') } const layer = locale.layers[params.layer] diff --git a/mod/workspace/getLocale.js b/mod/workspace/getLocale.js new file mode 100644 index 000000000..0ef979cc0 --- /dev/null +++ b/mod/workspace/getLocale.js @@ -0,0 +1,33 @@ +const Roles = require('../utils/roles') + +const merge = require('../utils/merge') + +const workspaceCache = require('./cache') + +const getTemplate = require('./getTemplate') + +module.exports = async (params) => { + + const workspace = await workspaceCache() + + if (!Object.hasOwn(workspace.locales, params.locale)) { + return new Error('Unable to validate locale param.') + } + + const locale = workspace.locales[params.locale] + + const roles = params.user?.roles || [] + + if (!Roles.check(locale, roles)) { + return new Error('Role access denied.') + } + + // A template exists for the locale key. + if (Object.hasOwn(workspace.templates, params.locale)) { + + // Merge the workspace template into workspace. + merge(locale, await getTemplate(workspace.templates[params.locale])) + } + + return locale +} \ No newline at end of file diff --git a/mod/workspace/templates/msgs.js b/mod/workspace/templates/msgs.js index 6c40c940d..fd48aaac9 100644 --- a/mod/workspace/templates/msgs.js +++ b/mod/workspace/templates/msgs.js @@ -1,116 +1,119 @@ module.exports = { - login_required: { - en: `Login required.` - }, - admin_required: { - en: `Admin priviliges required.` - }, - token_not_found: { - en: `Token not found. The token has probably been resolved already.`, - fr: `Token n’a pas été trouvé. Il a probablement déjà été utilisé.`, - pl: `Token wygasł. Prawdopodobnie został już wykorzystany.`, - ja: `トークンが見つかりません。 トークンはおそらくすでに解決されています。`, - ko: `토근이 발견되지 않았습니다. 이미 해결된 것 같습니다.`, - zh: `未找到相关令牌, 该令牌可能已解析` - }, - no_locales: { - en: `No accessible locales for user account.`, - de: `Keine Locale zugreifbar fuer den User.` - }, - password_reset_verification: { - en: `Password will be reset after email verification.`, - fr: `Le mot de passe sera réinitialisé après la vérification par e-mail.`, - pl: `Hasło zostanie ustawione po weryfikacji konta przez wiadomości e-mail.`, - ja: `E-メール検証完了後にパスワードはリセットされます`, - ko: `이메일 확인 후 비밀번호가 재설정됩니다`, - zh: `电子邮件验证后,密码将被重置。` - }, - new_account_registered: { - en: `A new account has been registered and is awaiting email verification.`, - fr: `Un nouveau compte a été enregistré et il attend la vérification par e-mail.`, - pl: `Nowe konto zostało zarejestrowane i czeka na weryfikację przez wiadomość email.`, - ja: `新規アカウントの登録完了にてE-メール検証待ち`, - ko: `새로운 계정이 등록되었고 이메일 확인을 기다리고 있습니다.`, - zh: `已注册一个新帐户,正在等待电子邮件验证。` - }, - no_cookie_found: { - en: `No cookie relating to this application found on request` - }, - update_ok: { - en: `Update successful`, - fr: `Cette mise à jour a réussi.`, - pl: `Uaktualniono.`, - ja: `アップデートに成功しました`, - ko: `업데이트가 성공적으로 진행되었습니다.`, - zh: `更新成功` - }, - account_await_approval: { - en: `This account has been verified but requires administrator approval.`, - fr: `Le compte a été verifié mais il doit être approuvé par l'administrateur. `, - pl: `Konto zostało zweryfikowane i musi zostać zatwierdzone przez administratora.`, - ja: `本アカウント検証完了。アドミニストレーター承認が必要となります`, - ko: `이 계정은 확인되었으나 관리자의 승인이 필요합니다.`, - zh: `此帐户已通过验证,但需要管理员批准。` - }, - password_reset_ok: { - en: `Password has been reset.`, - fr: `Le mot de passe a été réinitialisé.`, - pl: `Ustawiono nowe hasło.`, - ja: `パスワードがリセットされました`, - ko: `비밀번호가 재설정되었습니다.`, - zh: `密码已重设` - }, - auth_failed: { - en: `Authentication failed.`, - de: `Anmeldung gescheitert.` - }, - user_locked: { - en: `User account has been locked due to failed login attempts.`, - de: `Benutzerkonto gesperrt.` - }, - user_blocked: { - en: `User blocked`, - fr: `Cet utilisateur est bloqué.`, - pl: `Konto zostało zablokowane.`, - ja: `ユーザーがブロックされました`, - ko: `사용자 봉쇄`, - zh: `用户被阻止` - }, - user_expired: { - en: `User approval has expired. Please re-register.`, - fr: `Les droits d'accès ont expiré. Veuillez vous réenregistrer.`, - pl: `Prawo dostępu wygasło. Zarejestruj się poownie.`, - ja: `ユーザーの承認は期限切れです。 再登録してください。`, - ko: `사용자 승인이 만료되었습니다. 다시 등록하십시오.`, - zh: `用戶批准已過期。 請重新註冊。` - }, - user_not_verified: { - en: `User not verified or approved`, - fr: `L’utilisateur n’a pas été vérifié ou approuvé.`, - pl: `Konto niezweryfikowane ani zatwierdzone.`, - ja: `ユーザーは確認または承認されていません`, - ko: `사용자 미확인 또는 미승인`, - zh: `用户未经验证或批准` - }, - admin_approved: { - en: `The account has been approved by you. An email has been sent to the account holder.`, - pl: `Konto zostało zatwierdzone. Wysłano wiadomość na zarejestrowany adres e-mail.`, - fr: `Vous avez approuvé ce compte. Un e-mail a été envoyé au propriétaire du compte.`, - ja: `アカウントはあなたによって承認されました。 メールをアカウント所有者に送信しました。`, - ko: `귀하에 의해서 계정이 승인되었습니다. 계정 사용자에게 이메일이 발송되었습니다.`, - zh: `此帐户已被您批准。电子邮件已发送给帐户持有人` - }, - failed_query: { - en: `Failed to query PostGIS table.` - }, - missing_password: { - en: `Missing password`, - fr: `Mot de passe manquant`, - pl: `Nie podano hasła.` - }, - missing_email: { - en: `Missing email`, - fr: `E-mail manquant`, - pl: `Nie podano adresu e-mail.` - } + login_required: { + en: `Login required.` + }, + admin_required: { + en: `Admin priviliges required.` + }, + token_not_found: { + en: `Token not found. The token has probably been resolved already.`, + fr: `Token n’a pas été trouvé. Il a probablement déjà été utilisé.`, + pl: `Token wygasł. Prawdopodobnie został już wykorzystany.`, + ja: `トークンが見つかりません。 トークンはおそらくすでに解決されています。`, + ko: `토근이 발견되지 않았습니다. 이미 해결된 것 같습니다.`, + zh: `未找到相关令牌, 该令牌可能已解析` + }, + no_locale: { + en: `Locale not accessible.` + }, + no_locales: { + en: `No accessible locales for user account.`, + de: `Keine Locale zugreifbar fuer den User.` + }, + password_reset_verification: { + en: `Password will be reset after email verification.`, + fr: `Le mot de passe sera réinitialisé après la vérification par e-mail.`, + pl: `Hasło zostanie ustawione po weryfikacji konta przez wiadomości e-mail.`, + ja: `E-メール検証完了後にパスワードはリセットされます`, + ko: `이메일 확인 후 비밀번호가 재설정됩니다`, + zh: `电子邮件验证后,密码将被重置。` + }, + new_account_registered: { + en: `A new account has been registered and is awaiting email verification.`, + fr: `Un nouveau compte a été enregistré et il attend la vérification par e-mail.`, + pl: `Nowe konto zostało zarejestrowane i czeka na weryfikację przez wiadomość email.`, + ja: `新規アカウントの登録完了にてE-メール検証待ち`, + ko: `새로운 계정이 등록되었고 이메일 확인을 기다리고 있습니다.`, + zh: `已注册一个新帐户,正在等待电子邮件验证。` + }, + no_cookie_found: { + en: `No cookie relating to this application found on request` + }, + update_ok: { + en: `Update successful`, + fr: `Cette mise à jour a réussi.`, + pl: `Uaktualniono.`, + ja: `アップデートに成功しました`, + ko: `업데이트가 성공적으로 진행되었습니다.`, + zh: `更新成功` + }, + account_await_approval: { + en: `This account has been verified but requires administrator approval.`, + fr: `Le compte a été verifié mais il doit être approuvé par l'administrateur. `, + pl: `Konto zostało zweryfikowane i musi zostać zatwierdzone przez administratora.`, + ja: `本アカウント検証完了。アドミニストレーター承認が必要となります`, + ko: `이 계정은 확인되었으나 관리자의 승인이 필요합니다.`, + zh: `此帐户已通过验证,但需要管理员批准。` + }, + password_reset_ok: { + en: `Password has been reset.`, + fr: `Le mot de passe a été réinitialisé.`, + pl: `Ustawiono nowe hasło.`, + ja: `パスワードがリセットされました`, + ko: `비밀번호가 재설정되었습니다.`, + zh: `密码已重设` + }, + auth_failed: { + en: `Authentication failed.`, + de: `Anmeldung gescheitert.` + }, + user_locked: { + en: `User account has been locked due to failed login attempts.`, + de: `Benutzerkonto gesperrt.` + }, + user_blocked: { + en: `User blocked`, + fr: `Cet utilisateur est bloqué.`, + pl: `Konto zostało zablokowane.`, + ja: `ユーザーがブロックされました`, + ko: `사용자 봉쇄`, + zh: `用户被阻止` + }, + user_expired: { + en: `User approval has expired. Please re-register.`, + fr: `Les droits d'accès ont expiré. Veuillez vous réenregistrer.`, + pl: `Prawo dostępu wygasło. Zarejestruj się poownie.`, + ja: `ユーザーの承認は期限切れです。 再登録してください。`, + ko: `사용자 승인이 만료되었습니다. 다시 등록하십시오.`, + zh: `用戶批准已過期。 請重新註冊。` + }, + user_not_verified: { + en: `User not verified or approved`, + fr: `L’utilisateur n’a pas été vérifié ou approuvé.`, + pl: `Konto niezweryfikowane ani zatwierdzone.`, + ja: `ユーザーは確認または承認されていません`, + ko: `사용자 미확인 또는 미승인`, + zh: `用户未经验证或批准` + }, + admin_approved: { + en: `The account has been approved by you. An email has been sent to the account holder.`, + pl: `Konto zostało zatwierdzone. Wysłano wiadomość na zarejestrowany adres e-mail.`, + fr: `Vous avez approuvé ce compte. Un e-mail a été envoyé au propriétaire du compte.`, + ja: `アカウントはあなたによって承認されました。 メールをアカウント所有者に送信しました。`, + ko: `귀하에 의해서 계정이 승인되었습니다. 계정 사용자에게 이메일이 발송되었습니다.`, + zh: `此帐户已被您批准。电子邮件已发送给帐户持有人` + }, + failed_query: { + en: `Failed to query PostGIS table.` + }, + missing_password: { + en: `Missing password`, + fr: `Mot de passe manquant`, + pl: `Nie podano hasła.` + }, + missing_email: { + en: `Missing email`, + fr: `E-mail manquant`, + pl: `Nie podano adresu e-mail.` + } } \ No newline at end of file diff --git a/public/views/_default.js b/public/views/_default.js index 33a7149ae..133bf3b97 100644 --- a/public/views/_default.js +++ b/public/views/_default.js @@ -188,14 +188,21 @@ window.onload = async () => { // Get list of accessible locales from Workspace API. const locales = await mapp.utils.xhr(`${host}/api/workspace/locales`); - if (!locales.length) return alert('No accessible locales'); + if (!locales.length) { + + location.href = '?logout=true&msg=no_locales' + return; + } // Get locale with list of layers from Workspace API. const locale = await mapp.utils.xhr( - `${host}/api/workspace/locale?locale=${ - document.head.dataset.locale || mapp.hooks.current.locale || locales[0].key - }` - ); + `${host}/api/workspace/locale?locale=${mapp.hooks.current.locale || locales[0].key}`); + + if(locale instanceof Error){ + + location.href = '?logout=true&msg=no_locale' + return; + } // Add locale dropdown to layers panel if multiple locales are accessible. if (locales.length > 1) {