diff --git a/.gitignore b/.gitignore
index 3bff17f3e..898ae876f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,8 +4,8 @@
# Config files
server/src/configs/*
!server/src/configs/default.json
-!server/src/configs/config.example.json
!server/src/configs/areas.example.json
+!server/src/configs/local.example.json
.env
# Masterfile
diff --git a/Dockerfile b/Dockerfile
index fc7c78c04..5ab793208 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,7 @@
## Simple Dockerfile to build ReactMap (main branch)
# - Inside the container, the content of this git repo lives in /home/node/
## You have to mount your configs into the container:
-# - mount config.json to /home/node/server/src/configs/config.json
+# - mount local.json to /home/node/server/src/configs/local.json
# - mount areas.json to /home/node/server/src/configs/areas.json
# - Also mount every other configuration file necessary into the according directory.
diff --git a/docker-compose.example.yml b/docker-compose.example.yml
index 77327dbef..731605d66 100644
--- a/docker-compose.example.yml
+++ b/docker-compose.example.yml
@@ -7,7 +7,7 @@ services:
restart: unless-stopped
volumes:
- ./server/src/configs/areas.json:/home/node/server/src/configs/areas.json
- - ./server/src/configs/config.json:/home/node/server/src/configs/config.json
+ - ./server/src/configs/local.json:/home/node/server/src/local/config.json
- ./example.env:/home/node/.env
ports:
- "9090:8080"
diff --git a/package.json b/package.json
index 9f2c62e07..8d7fdd0a3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "reactmap",
- "version": "1.0.12",
+ "version": "1.0.13",
"description": "React based frontend map.",
"main": "index.js",
"author": "TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com>",
@@ -12,8 +12,9 @@
"dev": "nodemon server/src/index.js --watch server",
"build": "yarn create-locales && webpack --env prod",
"watch": "webpack --watch --env dev",
- "generate": "node server/src/services/generateMasterfile.js",
- "create-locales": "node server/src/services/createLocales.js",
+ "generate": "node server/scripts/generateMasterfile.js",
+ "create-locales": "node server/scripts/createLocales.js",
+ "config-migrate": "node server/scripts/configMigration.js",
"console": "node --experimental-repl-await ./server/src/console.js",
"migrate:make": "knex --knexfile server/knexfile.cjs migrate:make",
"migrate:latest": "knex --knexfile server/knexfile.cjs migrate:latest",
@@ -73,6 +74,7 @@
"apollo-server-express": "^3.5.0",
"bcrypt": "^5.0.1",
"compression": "^1.7.4",
+ "config": "^3.3.6",
"discord.js": "^12.5.3",
"express": "^4.17.1",
"express-mysql-session": "^2.1.6",
diff --git a/public/base-locales/de.json b/public/base-locales/de.json
index 8e9613330..9316aee56 100644
--- a/public/base-locales/de.json
+++ b/public/base-locales/de.json
@@ -111,7 +111,7 @@
"next_submission": "Nächster Vorschlag!",
"never": "nie",
"next_gym": "Nächste Arena",
- "s2cells": "S2 Zellen",
+ "scan_cells": "S2 Zellen",
"devices": "Geräte",
"use_my_location": "Meinen Standort verwenden",
"submit_feedback_title": "Feedback/Fehlerbericht senden",
@@ -277,7 +277,7 @@
"pvp_subtitle": "Zeigt PVP-Rang/WP/Level-Informationen für jedes Pokemon",
"quests_subtitle": "Zeigt Quest Belohnung und Aufgabeninformationen an",
"raids_subtitle": "Zeigt alle Raid-Informationen, einschließlich des Raid-Bosses, der Eier, der Ablaufzeit und des Movesets",
- "s2cells_subtitle": "Zeigt an, wann eine S2-Zelle zuletzt von einem Gerät gescannt wurde",
+ "scan_cells_subtitle": "Zeigt an, wann eine S2-Zelle zuletzt von einem Gerät gescannt wurde",
"scanAreas_subtitle": "Zeigt verfügbare Scanbereich Polygone",
"spawnpoints_subtitle": "Zeigt Spawnpunkte und deren geschätzte Despawnzeit an",
"stats_subtitle": "Zeigt Pokemon-Statistiken und Level an",
diff --git a/public/base-locales/en.json b/public/base-locales/en.json
index e8a9673f9..9bf53fee1 100644
--- a/public/base-locales/en.json
+++ b/public/base-locales/en.json
@@ -107,7 +107,7 @@
"next_submission": "Next Submission!",
"never": "Never",
"next_gym": "Next Gym",
- "s2cells": "S2 Cells",
+ "scan_cells": "Scan Cells",
"devices": "Devices",
"use_my_location": "Use My Location",
"submit_feedback_title": "Submit Feedback/Bug Report",
@@ -274,7 +274,7 @@
"pvp_subtitle": "Shows PVP rank/CP/Level info for each Pokémon",
"quests_subtitle": "Shows quest reward and task information",
"raids_subtitle": "Shows all raid info including the raid boss, eggs, expire time, and moveset",
- "s2cells_subtitle": "Shows the last time a S2 cell was scanned by a device",
+ "scan_cells_subtitle": "Shows the last time a S2 cell was scanned by a device",
"scanAreas_subtitle": "Shows available scan areas polygons",
"spawnpoints_subtitle": "Shows spawnpoints and their estimated despawn time",
"stats_subtitle": "Shows Pokémon stats and levels",
diff --git a/public/base-locales/es.json b/public/base-locales/es.json
index a984dfb92..957fd32a5 100644
--- a/public/base-locales/es.json
+++ b/public/base-locales/es.json
@@ -108,7 +108,7 @@
"next_submission": "Sumisión Siguiente!",
"never": "Nunca",
"next_gym": "Siguiente Gimnasio",
- "s2cells": "S2cells",
+ "scan_cells": "S2cells",
"devices": "Aparato",
"use_my_location": "Usar Mi Puesto",
"submit_feedback_title": "Enviar omentarios o reportar errores",
@@ -270,7 +270,7 @@
"pvp_subtitle": "Muestra la información de PVP para cada Pokémon",
"quests_subtitle": "Muestra la información de las misiones",
"raids_subtitle": "Muestra la información de las Incursiones",
- "s2cells_subtitle": "Muestra la última vez que una celda S2 fue escaneada por un dispositivo",
+ "scan_cells_subtitle": "Muestra la última vez que una celda S2 fue escaneada por un dispositivo",
"scanAreas_subtitle": "Muestra los polígonos de áreas de escaneo disponibles",
"spawnpoints_subtitle": "Muestra las ubicaciones de los spawns y las horas de expiración",
"stats_subtitle": "Muestra las estadísticas de los Pokémon",
diff --git a/public/base-locales/fr.json b/public/base-locales/fr.json
index c08666d95..8bdfa512a 100644
--- a/public/base-locales/fr.json
+++ b/public/base-locales/fr.json
@@ -111,7 +111,7 @@
"next_submission": "Prochaine Soumission!",
"never": "Jamais",
"next_gym": "Prochaine Arène",
- "s2cells": "S2cells",
+ "scan_cells": "S2cells",
"devices": "Appareils",
"use_my_location": "Utiliser Ma Position",
"submit_feedback_title": "Envoyer Commentaire/Rapport de bug",
@@ -276,7 +276,7 @@
"pvp_subtitle": "Affiche les infos PVP/PC/Niveau pour chaque Pokemon",
"quests_subtitle": "Affiche les récompenses de quêtes et tâches",
"raids_subtitle": "Affiche les info de raid y compris le Boss, Oeufs, heure d'expiration et attaques",
- "s2cells_subtitle": "Affiche la denière fois ou la cellule S2 à été scannées",
+ "scan_cells_subtitle": "Affiche la denière fois ou la cellule S2 à été scannées",
"scanAreas_subtitle": "Affiche les zones de scan",
"spawnpoints_subtitle": "Affiche les points d'apparition et les heure d'expiration estimée",
"stats_subtitle": "Affiche les Stats et Niveaux des Pokemon",
diff --git a/public/base-locales/nl.json b/public/base-locales/nl.json
index 56b624d55..448c0a432 100644
--- a/public/base-locales/nl.json
+++ b/public/base-locales/nl.json
@@ -107,7 +107,7 @@
"next_submission": "Volgende Inzending!",
"never": "Nooit",
"next_gym": "Volgende Gym",
- "s2cells": "S2 Cells",
+ "scan_cells": "S2 Cells",
"devices": "Apparaten",
"use_my_location": "Gebruik Mijn Locatie",
"submit_feedback_title": "Feedback/Bug Rapport Indienen",
@@ -274,7 +274,7 @@
"pvp_subtitle": "Toont PVP rank/CP/Level informatie voor elke Pokémon",
"quests_subtitle": "Toont quest reward en task informatie",
"raids_subtitle": "Toont alle raid informatie inclusief de raid boss, eggs, vervaltijd, en moveset",
- "s2cells_subtitle": "Toont de laatste tijd een S2 cell was bijgewerkt door een scanner.",
+ "scan_cells_subtitle": "Toont de laatste tijd een S2 cell was bijgewerkt door een scanner.",
"scanAreas_subtitle": "Toont beschikbare scan gebieden polygons",
"spawnpoints_subtitle": "Toont spawnpoints en hun geschatte despawntijd",
"stats_subtitle": "Toont Pokémon Statistieken en levels",
diff --git a/public/base-locales/pl.json b/public/base-locales/pl.json
index 286f77374..29ab90def 100644
--- a/public/base-locales/pl.json
+++ b/public/base-locales/pl.json
@@ -110,7 +110,7 @@
"next_submission": "Kolejne zgłoszenie!",
"never": "Nigdy",
"next_gym": "Kolejny gym",
- "s2cells": "Komórki S2",
+ "scan_cells": "Komórki S2",
"devices": "Urządzenia",
"use_my_location": "Użyj bieżącej lokalizacji",
"submit_feedback_title": "Prześlij komentarz / Zgłoś błąd",
@@ -276,7 +276,7 @@
"pvp_subtitle": "Pokazuje rangę PVP/CP/informację o poziomie każdego Pokemona",
"quests_subtitle": "Pokazuje nagrodę oraz informację o zadaniu",
"raids_subtitle": "Pokazuje dane raidu, takie jak informacja o bossie, jajku, czasie zakończenia czy atakach bossa",
- "s2cells_subtitle": "Pokazuje czas ostatniego skanowania komórki S2 przez urządzenie",
+ "scan_cells_subtitle": "Pokazuje czas ostatniego skanowania komórki S2 przez urządzenie",
"scanAreas_subtitle": "Pokazuje dostępne obszary skanowania",
"spawnpoints_subtitle": "Pokazuje spawnpointy oraz ich przybliżone czasy despawnu",
"stats_subtitle": "Pokazuje statystyki i poziomy Pokemona",
diff --git a/public/images/perms/s2cells.png b/public/images/perms/scanCells.png
similarity index 100%
rename from public/images/perms/s2cells.png
rename to public/images/perms/scanCells.png
diff --git a/server/knexfile.cjs b/server/knexfile.cjs
index f4fb07aad..6dee22b14 100644
--- a/server/knexfile.cjs
+++ b/server/knexfile.cjs
@@ -1,18 +1,24 @@
+/* eslint-disable no-console */
const path = require('path')
const { database: { schemas, settings: { migrationTableName } } } = require('./src/services/config')
const migrationUrl = 'src/db/migrations'
-const selectedDb = Object.keys(schemas).find(dbName => schemas[dbName].useFor.includes('user')) || Object.keys(schemas)[0]
+const selectedDb = schemas.find(db => db.useFor.includes('user'))
+
+if (!selectedDb) {
+ console.warn('No database selected for React Map Tables')
+ process.exit(9)
+}
const connection = {
client: 'mysql2',
connection: {
- host: schemas[selectedDb].host,
- port: schemas[selectedDb].port,
- user: schemas[selectedDb].username,
- password: schemas[selectedDb].password,
- database: schemas[selectedDb].database,
+ host: selectedDb.host,
+ port: selectedDb.port,
+ user: selectedDb.username,
+ password: selectedDb.password,
+ database: selectedDb.database,
},
migrations: {
tableName: migrationTableName,
diff --git a/server/scripts/configMigration.js b/server/scripts/configMigration.js
new file mode 100644
index 000000000..be3faa9b8
--- /dev/null
+++ b/server/scripts/configMigration.js
@@ -0,0 +1,381 @@
+/* eslint-disable no-console */
+const fs = require('fs')
+const oldConfig = require('../src/configs/config.json')
+
+const convertObjToArr = (obj) => obj ? Object.entries(obj).map(([k, v]) => ({
+ name: k,
+ ...v,
+})) : undefined
+
+const convertMapObject = (obj) => ({
+ general: {
+ title: obj?.title,
+ headerTitle: obj?.headerTitle,
+ startLat: obj?.startLat,
+ startLon: obj?.startLon,
+ startZoom: obj?.startZoom,
+ minZoom: obj?.minZoom,
+ maxZoom: obj?.maxZoom,
+ interactionRangeZoom: obj?.interactionRangeZoom,
+ },
+ localeSelection: obj?.localeSelection,
+ customRoutes: {
+ discordAuthUrl: obj?.discordAuthUrl,
+ telegramAuthUrl: obj?.telegramAuthUrl,
+ telegramBotEnvRef: obj?.telegramBotEnvRef,
+ localAuthUrl: obj?.localAuthUrl,
+ },
+ links: {
+ discordInvite: obj?.discordInvite,
+ feedbackLink: obj?.feedbackLink,
+ statsLink: obj?.statsLink,
+ rolesLinksName: obj?.rolesLinksName,
+ rolesLink: obj?.rolesLink,
+ },
+ holidayEffects: {
+ christmasSnow: obj?.christmasSnow,
+ newYearsFireworks: obj?.newYearsFireworks,
+ valentinesDay: obj?.valentinesDay,
+ },
+ misc: {
+ enableMapJsFilter: obj?.legacyPkmnFilter,
+ questRewardTypeFilters: obj?.questRewardTypeFilters,
+ fetchLatestInvasions: obj?.fetchLatestInvasions,
+ invasionCacheHrs: obj?.invasionCacheHrs,
+ navigationControls: obj?.navigationControls,
+ forceTutorial: obj?.forceTutorial,
+ enableTutorial: obj?.enableTutorial,
+ enableUserProfile: obj?.enableUserProfile,
+ enableQuestSetSelector: obj?.enableQuestSetSelector,
+ },
+ theme: obj?.theme,
+ clustering: {
+ gyms: {
+ zoomLevel: obj?.clusterZoomLevels?.gyms,
+ forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit,
+ },
+ pokestops: {
+ zoomLevel: obj?.clusterZoomLevels?.pokestops,
+ forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit,
+ },
+ pokemon: {
+ zoomLevel: obj?.clusterZoomLevels?.pokemon,
+ forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit,
+ },
+ portals: {
+ zoomLevel: obj?.clusterZoomLevels?.portals,
+ forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit,
+ },
+ spawnpoints: {
+ zoomLevel: obj?.clusterZoomLevels?.spawnpoints,
+ forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit,
+ },
+ },
+ messageOfTheDay: obj.messageOfTheDay
+ ? ensureMotd(obj?.messageOfTheDay)
+ : undefined,
+ donationPage: obj?.donationPage,
+ loginPage: obj?.loginPage,
+})
+
+const ensureMotd = (obj) => {
+ if (obj.messages) {
+ const updateFieldRec = (messages) => messages.map(message => {
+ if (message.messages) {
+ message.components = updateFieldRec(message.messages)
+ delete message.messages
+ }
+ return message
+ })
+ obj.components = obj.messages.map(m => {
+ if (m.type !== 'parent') return m
+ if (m.messages) {
+ m.components = m.components || updateFieldRec(m.messages)
+ delete m.messages
+ }
+ return m
+ })
+ delete obj.messages
+ }
+ return obj
+}
+
+const mergeAuth = async () => {
+ let authMethods = await fs.promises.readdir(`${__dirname}/../src/strategies`)
+ .then(files => files
+ .filter(file => file !== 'local.js' && file !== 'discord.js' && file !== 'telegram.js'))
+ if (authMethods?.length) {
+ authMethods = authMethods.map(file => file.replace('.js', ''))
+ console.log('Found Custom Auth Methods:', authMethods, '\n', 'You should double check these were migrated correctly!')
+ }
+
+ const flattenArray = (perm) => ([
+ ...oldConfig?.discord?.perms?.[perm]?.roles || [],
+ ...oldConfig?.telegram?.perms?.[perm]?.roles || [],
+ ...authMethods.flatMap(m => oldConfig?.[m]?.perms[perm]?.roles || []),
+ ])
+
+ const discordObj = (obj, name) => ({
+ name,
+ enabled: obj?.enabled,
+ type: 'discord',
+ logChannelId: obj?.logChannelId,
+ presence: obj?.presence,
+ presenceType: obj?.presenceType,
+ botToken: obj?.botToken,
+ clientId: obj?.clientId,
+ clientSecret: obj?.clientSecret,
+ redirectUri: obj?.redirectUri,
+ allowedGuilds: obj?.allowedGuilds,
+ blockedGuilds: obj?.blockedGuilds,
+ allowedUsers: obj?.allowedUsers,
+ })
+
+ const telegramObj = (obj, name) => ({
+ name,
+ enabled: obj?.enabled,
+ type: 'telegram',
+ botToken: obj?.botToken,
+ groups: obj?.groups,
+ })
+
+ const localObj = (obj, name) => ({
+ name,
+ enabled: obj?.enabled,
+ type: 'local',
+ })
+
+ const checkEnabled = (perm) => oldConfig?.discord?.perms?.[perm]?.enabled
+ || oldConfig?.telegram?.perms?.[perm]?.enabled
+
+ const baseAuth = {
+ strategies: [],
+ areaRestrictions: [
+ ...oldConfig?.discord?.areaRestrictions || [],
+ ...oldConfig?.telegram?.areaRestrictions || [],
+ ...oldConfig?.local?.areaRestrictions || [],
+ ...authMethods.flatMap(m => oldConfig?.[m]?.areaRestrictions || []),
+ ],
+ excludeFromTutorial: oldConfig?.excludeFromTutorial
+ ? oldConfig.excludeFromTutorial.map(perm => perm === 's2cells' ? 'scanCells' : perm)
+ : undefined,
+ alwaysEnabledPerms: oldConfig?.alwaysEnabledPerms
+ ? oldConfig.alwaysEnabledPerms.map(perm => perm === 's2cells' ? 'scanCells' : perm)
+ : undefined,
+ perms: {
+ map: {
+ enabled: checkEnabled('map'),
+ roles: flattenArray('map'),
+ },
+ pokemon: {
+ enabled: checkEnabled('pokemon'),
+ roles: flattenArray('pokemon'),
+ },
+ iv: {
+ enabled: checkEnabled('iv'),
+ roles: flattenArray('iv'),
+ },
+ pvp: {
+ enabled: checkEnabled('pvp'),
+ roles: flattenArray('pvp'),
+ },
+ gyms: {
+ enabled: checkEnabled('gyms'),
+ roles: flattenArray('gyms'),
+ },
+ raids: {
+ enabled: checkEnabled('raids'),
+ roles: flattenArray('raids'),
+ },
+ pokestops: {
+ enabled: checkEnabled('pokestops'),
+ roles: flattenArray('pokestops'),
+ },
+ quests: {
+ enabled: checkEnabled('quests'),
+ roles: flattenArray('quests'),
+ },
+ lures: {
+ enabled: checkEnabled('lures'),
+ roles: flattenArray('lures'),
+ },
+ portals: {
+ enabled: checkEnabled('portals'),
+ roles: flattenArray('portals'),
+ },
+ submissionCells: {
+ enabled: checkEnabled('submissionCells'),
+ roles: flattenArray('submissionCells'),
+ },
+ invasions: {
+ enabled: checkEnabled('invasions'),
+ roles: flattenArray('invasions'),
+ },
+ nests: {
+ enabled: checkEnabled('nests'),
+ roles: flattenArray('nests'),
+ },
+ scanAreas: {
+ enabled: checkEnabled('scanAreas'),
+ roles: flattenArray('scanAreas'),
+ },
+ weather: {
+ enabled: checkEnabled('weather'),
+ roles: flattenArray('weather'),
+ },
+ spawnpoints: {
+ enabled: checkEnabled('spawnpoints'),
+ roles: flattenArray('spawnpoints'),
+ },
+ scanCells: {
+ enabled: checkEnabled('scanCells'),
+ roles: flattenArray('s2cells'),
+ },
+ devices: {
+ enabled: checkEnabled('devices'),
+ roles: flattenArray('devices'),
+ },
+ donor: {
+ enabled: checkEnabled('donor'),
+ roles: flattenArray('donor'),
+ },
+ },
+ }
+ if (oldConfig?.discord) {
+ baseAuth.strategies.push(discordObj(oldConfig?.discord, 'discord'))
+ }
+ if (oldConfig?.telegram) {
+ baseAuth.strategies.push(telegramObj(oldConfig?.telegram, 'telegram'))
+ }
+ if (oldConfig?.local) {
+ baseAuth.strategies.push(localObj(oldConfig?.local, 'local'))
+ if (oldConfig?.local?.perms) {
+ oldConfig.local.perms.forEach(perm => {
+ if (perm === 's2cells') {
+ baseAuth.perms.scanCell.roles.push('local')
+ } else {
+ Object.keys(baseAuth.perms).forEach(key => {
+ if (perm.includes(key)) {
+ baseAuth.perms[key].roles.push('local')
+ }
+ })
+ }
+ })
+ }
+ }
+ authMethods.forEach(m => {
+ if (m.toLowerCase().includes('discord')) {
+ baseAuth.strategies.push(discordObj(oldConfig[m], m))
+ } else if (m.toLowerCase().includes('telegram')) {
+ baseAuth.strategies.push(telegramObj(oldConfig[m], m))
+ } else if (m.toLowerCase().includes('local')) {
+ baseAuth.strategies.push(localObj(oldConfig[m], m))
+ } else {
+ console.warn('Unable to process Auth Method:', m, 'you will need to manually migrate this!')
+ }
+ })
+ return baseAuth
+}
+
+const rebuildConfig = async () => ({
+ interface: oldConfig?.interface,
+ port: oldConfig?.port,
+ devOptions: oldConfig?.devOptions,
+ api: {
+ ...oldConfig?.api,
+ pvpMinCp: undefined,
+ sessionSecret: `${oldConfig?.api?.sessionSecret}x`,
+ pvp: {
+ leagues: oldConfig?.database?.settings?.leagues,
+ levels: oldConfig?.database?.settings?.pvpLevels,
+ reactMapHandlesPvp: oldConfig?.database?.settings?.reactMapHandlesPvp,
+ minCp: {
+ ...oldConfig?.api?.pvpMinCp,
+ },
+ },
+ },
+ multiDomains: oldConfig.multiDomains
+ ? Object.entries(oldConfig.multiDomains).map(([domain, values]) => ({
+ domain,
+ ...convertMapObject(values),
+ }))
+ : undefined,
+ map: convertMapObject(oldConfig?.map),
+ clientSideOptions: oldConfig?.clientSideOptions,
+ defaultFilters: oldConfig?.defaultFilters ? {
+ ...oldConfig?.defaultFilters,
+ pokemon: {
+ ...oldConfig?.defaultFilters?.pokemon,
+ globalValues: {
+ ...oldConfig?.defaultFilters?.pokemon?.globalValues,
+ pvp: oldConfig?.defaultFilters?.pokemon?.pvpValues,
+ },
+ pvpValues: undefined,
+ },
+ } : undefined,
+ database: {
+ settings: {
+ ...oldConfig?.database?.settings,
+ leagues: undefined,
+ reactMapHandlesPvp: undefined,
+ pvpLevels: undefined,
+ },
+ schemas: Object.values(oldConfig?.database?.schemas).map(s => {
+ if (s.useFor.includes('s2cell')) {
+ const s2cellIndex = s.useFor.indexOf('s2cell')
+ s.useFor[s2cellIndex] = 'scanCell'
+ }
+ return s
+ }),
+ },
+ webhooks: oldConfig?.webhooks,
+ authentication: await mergeAuth(),
+ tileServers: convertObjToArr(oldConfig?.tileServers),
+ navigation: convertObjToArr(oldConfig?.navigation),
+ icons: oldConfig?.icons,
+ rarity: oldConfig?.rarity,
+ manualAreas: convertObjToArr(oldConfig?.manualAreas),
+})
+
+const cleanConfig = (obj, round) => {
+ Object.entries(obj).forEach(([key, value]) => {
+ if (Array.isArray(value)) {
+ value.forEach(subObj => {
+ if (typeof subObj === 'object') {
+ cleanConfig(subObj, round)
+ }
+ })
+ } else if (typeof value === 'object') {
+ if (!Object.keys(value).length || Object.values(value).every(v => v === undefined)) {
+ delete obj[key]
+ console.log('Removed empty object:', key, round)
+ } else {
+ cleanConfig(value, round)
+ }
+ }
+ })
+}
+
+const migrator = async () => {
+ const config = await rebuildConfig()
+ cleanConfig(config, '(1)')
+ cleanConfig(config, '(2)')
+ if (config?.tileServers?.length === 0) {
+ delete config.tileServers
+ }
+ if (config?.navigation?.length === 0) {
+ delete config.navigation
+ }
+ fs.writeFileSync(
+ `${__dirname}/../src/configs/local.json`,
+ JSON.stringify(config, null, 2),
+ 'utf8',
+ () => { },
+ )
+}
+
+module.exports.migrator = migrator
+
+if (require.main === module) {
+ migrator().then(() => console.log('Migrated Config'))
+}
diff --git a/server/src/console.js b/server/scripts/console.js
similarity index 58%
rename from server/src/console.js
rename to server/scripts/console.js
index 82b84e5d1..eb15cff7f 100644
--- a/server/src/console.js
+++ b/server/scripts/console.js
@@ -1,6 +1,6 @@
const repl = require('repl')
-require('./db/initialization')
-const models = require('./models/index')
+require('../src/db/initialization')
+const models = require('../src/models/index')
const replServer = repl.start({
prompt: '> ',
diff --git a/server/src/services/createLocales.js b/server/scripts/createLocales.js
similarity index 91%
rename from server/src/services/createLocales.js
rename to server/scripts/createLocales.js
index ce262e1d0..a6e816f1f 100644
--- a/server/src/services/createLocales.js
+++ b/server/scripts/createLocales.js
@@ -2,10 +2,10 @@
const fs = require('fs')
const path = require('path')
-const fetchJson = require('./api/fetchJson')
+const fetchJson = require('../src/services/api/fetchJson')
-const appLocalesFolder = path.resolve(__dirname, '../../../public/base-locales')
-const finalLocalesFolder = path.resolve(__dirname, '../../../public/locales')
+const appLocalesFolder = path.resolve(__dirname, '../../public/base-locales')
+const finalLocalesFolder = path.resolve(__dirname, '../../public/locales')
const locales = async () => {
const localTranslations = await fs.promises.readdir(appLocalesFolder)
diff --git a/server/src/services/generateMasterfile.js b/server/scripts/generateMasterfile.js
similarity index 71%
rename from server/src/services/generateMasterfile.js
rename to server/scripts/generateMasterfile.js
index a3cee2580..ff8b50d65 100644
--- a/server/src/services/generateMasterfile.js
+++ b/server/scripts/generateMasterfile.js
@@ -2,16 +2,16 @@
/* eslint-disable no-restricted-syntax */
const fs = require('fs')
-const fetchJson = require('./api/fetchJson')
-const defaultRarity = require('../data/defaultRarity.json')
+const fetchJson = require('../src/services/api/fetchJson')
+const defaultRarity = require('../src/data/defaultRarity.json')
const getRarityLevel = (id, pkmn) => {
- const adminRarity = fs.existsSync('../configs/config.json')
- ? JSON.parse(fs.readFileSync('server/src/configs/config.json', 'utf8'))
- : JSON.parse(fs.readFileSync('server/src/configs/default.json', 'utf8'))
+ const adminRarity = fs.existsSync(`${__dirname}/../src/configs/local.json`)
+ ? JSON.parse(fs.readFileSync(`${__dirname}/../src/configs/local.json`, 'utf8'))
+ : JSON.parse(fs.readFileSync(`${__dirname}/../src/configs/default.json`, 'utf8'))
let rarity
for (const [tier, pokemon] of Object.entries(defaultRarity)) {
- if (adminRarity.rarity[tier].length > 0) {
+ if (adminRarity?.rarity?.[tier]?.length) {
if (adminRarity.rarity[tier].includes((parseInt(id)))) {
rarity = tier
}
@@ -36,13 +36,13 @@ const generate = async () => {
})
fs.writeFile(
- 'server/src/data/masterfile.json',
+ `${__dirname}/../src/data/masterfile.json`,
JSON.stringify(masterfile, null, 2),
'utf8',
() => { },
)
} catch (e) {
- console.warn('Unable to generate new masterfile, using existing.')
+ console.warn('Unable to generate new masterfile, using existing.', e)
}
}
diff --git a/server/src/configs/default.json b/server/src/configs/default.json
index 6088402ba..d6c7b932a 100644
--- a/server/src/configs/default.json
+++ b/server/src/configs/default.json
@@ -1,14 +1,6 @@
{
"interface": "0.0.0.0",
"port": 8080,
- "localeSelection": [
- "en",
- "de",
- "pl",
- "es",
- "fr",
- "nl"
- ],
"devOptions": {
"enabled": false,
"graphiql": false,
@@ -23,72 +15,118 @@
"time": 60,
"requests": 1000
},
- "pvpMinCp": {
- "great": 1400,
- "ultra": 2400
- },
"queryAvailable": {
- "pokemon": true,
- "quests": false,
- "raids": false,
- "nests": false
+ "pokemon": false,
+ "quest": true,
+ "raid": true,
+ "nest": false
+ },
+ "pvp": {
+ "leagues": [
+ {
+ "name": "great",
+ "cp": 1500
+ },
+ {
+ "name": "ultra",
+ "cp": 2500
+ }
+ ],
+ "levels": [
+ 50,
+ 51
+ ],
+ "reactMapHandlesPvp": false,
+ "minCp": {
+ "great": 1400,
+ "ultra": 2400
+ }
},
"portalUpdateLimit": 30,
"weatherCellLimit": 3,
- "searchResultsLimit": 15
+ "searchResultsLimit": 15,
+ "nestHemisphere": "north"
},
- "multiDomains": {},
+ "multiDomains": [],
"map": {
- "title": "ReactMap",
- "headerTitle": "ReactMap",
- "nestHemisphere": "north",
- "enableFeedback": false,
- "feedbackLink": "https://forms.gle/wKqWRs9Z7XEAPB7AA",
- "enableStats": false,
- "statsLink": "https://rdmopole2link.net",
- "rolesLinkName": "Role Upgrading Info",
- "rolesLink": "https://discordsomething.net",
- "forceTutorial": true,
- "enableTutorial": true,
- "enableUserProfile": true,
- "startLat": 0,
- "startLon": 0,
- "startZoom": 12,
- "minZoom": 10,
- "maxZoom": 18,
- "noScanAreaOverlay": false,
- "interactionRangeZoom": 15,
- "scanAreasZoom": 12,
- "scanCellsZoom": 13,
- "submissionZoom": 15,
- "legacyPkmnFilter": true,
- "enableQuestRewardTypeFilters": false,
- "enableQuestSetSelector": false,
- "fetchLatestInvasions": true,
- "invasionCacheHrs": 1,
- "questMessage": "",
- "navigationControls": "react",
- "discordInvite": "",
- "discordAuthUrl": "/auth/discord/callback",
- "telegramAuthUrl": "/auth/telegram/callback",
- "telegramBotEnvRef": "TELEGRAM_BOT_NAME",
- "localAuthUrl": "/auth/local/callback",
+ "general": {
+ "title": "ReactMap",
+ "headerTitle": "ReactMap",
+ "startLat": 0,
+ "startLon": 0,
+ "startZoom": 12,
+ "minZoom": 10,
+ "maxZoom": 18,
+ "interactionRangeZoom": 15,
+ "scanAreasZoom": 12,
+ "scanCellsZoom": 13,
+ "submissionZoom": 15
+ },
+ "localeSelection": [
+ "en",
+ "de",
+ "pl",
+ "es",
+ "fr",
+ "nl"
+ ],
+ "customRoutes": {
+ "discordAuthUrl": "/auth/discord/callback",
+ "telegramAuthUrl": "/auth/telegram/callback",
+ "telegramBotEnvRef": "TELEGRAM_BOT_NAME",
+ "localAuthUrl": "/auth/local/callback"
+ },
+ "links": {
+ "discordInvite": "",
+ "feedbackLink": "",
+ "statsLink": "",
+ "rolesLinkName": "Role Upgrading Info",
+ "rolesLink": ""
+ },
+ "holidayEffects": {
+ "christmasSnow": true,
+ "newYearsFireworks": true,
+ "valentinesDay": true
+ },
+ "misc": {
+ "enableMapJsFilter": true,
+ "questRewardTypeFilters": false,
+ "fetchLatestInvasions": true,
+ "invasionCacheHrs": 1,
+ "questMessage": "",
+ "navigationControls": "react",
+ "forceTutorial": true,
+ "enableTutorial": true,
+ "enableUserProfile": true,
+ "enableQuestSetSelector": false
+ },
"theme": {
"style": "dark",
"primary": "#ff5722",
"secondary": "#00b0ff",
"drawer": "temporary"
},
- "christmasSnow": true,
- "newYearsFireworks": true,
- "valentinesDay": true,
- "clusterZoomLevels": {
- "forcedClusterLimit": 2500,
- "gyms": 13,
- "pokestops": 14,
- "pokemon": 15,
- "portals": 14,
- "spawnpoints": 12
+ "clustering": {
+ "gyms": {
+ "zoomLevel": 13,
+ "forcedLimit": 2500
+ },
+ "pokestops": {
+ "zoomLevel": 14,
+ "forcedLimit": 2500
+ },
+ "pokemon": {
+ "zoomLevel": 15,
+ "forcedLimit": 3000
+ },
+ "portals": {
+ "zoomLevel": 14,
+ "forcedLimit": 3000
+ },
+ "spawnpoints": {
+ "zoomLevel": 12,
+ "forcedLimit": 5000
+ }
},
"messageOfTheDay": {
"index": 0,
@@ -244,12 +282,12 @@
"sta_iv": [
0,
15
+ ],
+ "pvp": [
+ 1,
+ 10
]
- },
- "pvpValues": [
- 1,
- 10
- ]
+ }
},
"portals": {
"enabled": false
@@ -275,14 +313,11 @@
"userTableName": "users",
"sessionTableName": "session",
"migrationTableName": "knex_migrations",
- "leagues": [],
- "reactMapHandlesPvp": false,
- "pvpLevels": [],
- "hideOldQuests": true,
+ "hideOldQuests": false,
"maxConnections": 10
},
- "schemas": {
- "scanner": {
+ "schemas": [
+ {
"type": "rdm",
"host": "127.0.0.1",
"port": 3306,
@@ -290,11 +325,10 @@
"password": "pass123!",
"database": "rdmdb",
"charset": "utf8mb4",
- "arScanColumn": false,
"hasAltQuests": false,
"useFor": []
},
- "manual": {
+ {
"type": "manual",
"host": "127.0.0.1",
"port": 3306,
@@ -302,27 +336,44 @@
"password": "pass123!",
"database": "manualdb",
"charset": "utf8mb4",
- "arScanColumn": false,
"useFor": []
}
- }
+ ]
},
"webhooks": [],
- "excludeFromTutorial": [],
- "alwaysEnabledPerms": [],
- "discord": {
- "enabled": false,
- "logChannelId": "",
- "presence": "Map Status: Online",
- "presenceType": 3,
- "botToken": "",
- "clientId": "",
- "clientSecret": "",
- "redirectUri": "http://localhost:8080/auth/discord/callback",
- "allowedGuilds": [],
- "blockedGuilds": [],
- "allowedUsers": [],
+ "authentication": {
+ "strategies": [
+ {
+ "name": "discord",
+ "type": "discord",
+ "enabled": false,
+ "logChannelId": "",
+ "presence": "Map Status: Online",
+ "presenceType": 3,
+ "botToken": "",
+ "clientId": "",
+ "clientSecret": "",
+ "redirectUri": "http://localhost:8080/auth/discord/callback",
+ "allowedGuilds": [],
+ "blockedGuilds": [],
+ "allowedUsers": []
+ },
+ {
+ "name": "telegram",
+ "type": "telegram",
+ "enabled": false,
+ "botToken": "",
+ "groups": []
+ },
+ {
+ "name": "local",
+ "type": "local",
+ "enabled": false
+ }
+ ],
"areaRestrictions": [],
+ "excludeFromTutorial": [],
+ "alwaysEnabledPerms": [],
"perms": {
"map": {
"enabled": true,
@@ -332,10 +383,6 @@
"enabled": true,
"roles": []
},
- "stats": {
- "enabled": true,
- "roles": []
- },
"iv": {
"enabled": true,
"roles": []
@@ -392,95 +439,7 @@
"enabled": true,
"roles": []
},
- "s2cells": {
- "enabled": true,
- "roles": []
- },
- "devices": {
- "enabled": true,
- "roles": []
- },
- "donor": {
- "enabled": true,
- "roles": []
- }
- }
- },
- "telegram": {
- "enabled": false,
- "botToken": "",
- "groups": [],
- "areaRestrictions": [],
- "perms": {
- "map": {
- "enabled": true,
- "roles": []
- },
- "gyms": {
- "enabled": true,
- "roles": []
- },
- "raids": {
- "enabled": true,
- "roles": []
- },
- "nests": {
- "enabled": true,
- "roles": []
- },
- "pokestops": {
- "enabled": true,
- "roles": []
- },
- "quests": {
- "enabled": true,
- "roles": []
- },
- "lures": {
- "enabled": true,
- "roles": []
- },
- "invasions": {
- "enabled": true,
- "roles": []
- },
- "pokemon": {
- "enabled": true,
- "roles": []
- },
- "stats": {
- "enabled": true,
- "roles": []
- },
- "iv": {
- "enabled": true,
- "roles": []
- },
- "pvp": {
- "enabled": true,
- "roles": []
- },
- "portals": {
- "enabled": true,
- "roles": []
- },
- "submissionCells": {
- "enabled": true,
- "roles": []
- },
- "scanAreas": {
- "enabled": true,
- "roles": []
- },
- "weather": {
- "enabled": true,
- "roles": []
- },
- "s2cells": {
- "enabled": true,
- "roles": []
- },
- "spawnpoints": {
+ "scanCells": {
"enabled": true,
"roles": []
},
@@ -494,47 +453,65 @@
}
}
},
- "local": {
- "enabled": false,
- "perms": [],
- "areaRestrictions": []
- },
- "tileServers": {
- "Default": {
+ "tileServers": [
+ {
+ "name": "auto"
+ },
+ {
+ "name": "Carto",
"attribution": "Map tiles by Carto, under CC BY 3.0. Data by OpenStreetMap, under ODbL.",
"url": "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
"style": "light"
},
- "OSM": {
+ {
+ "name": "OSM",
"attribution": "Map data © OpenStreetMap contributors",
"url": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"style": "light"
},
- "DarkMatter": {
+ {
+ "name": "Dark Matter",
"attribution": "© OpenStreetMap contributors © CARTO",
"url": "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
"style": "dark"
},
- "Satellite": {
+ {
+ "name": "Satellite",
"attribution": "© Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community",
"url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
"style": "dark"
+ },
+ {
+ "name": "AlidadeSmoothDark",
+ "attribution": "© Stadia Maps, © OpenMapTiles © OpenStreetMap contributors",
+ "url": "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png",
+ "style": "dark"
+ },
+ {
+ "name": "ThunderForest",
+ "attribution": "© Thunderforest, © OpenStreetMap contributors",
+ "url": "https://{s}.tile.thunderforest.com/transport-dark/{z}/{x}/{y}.png",
+ "style": "dark"
}
- },
- "navigation": {
- "GoogleMaps": {
+ ],
+ "navigation": [
+ {
+ "name": "Google Maps",
"url": "https://www.google.com/maps/place/{x},{y}"
},
- "AppleMaps": {
+ {
+ "name": "Apple Maps",
"url": "https://maps.apple.com/maps?daddr={x},{y}"
},
- "Waze": {
+ {
+ "name": "Waze",
"url": "https://www.waze.com/ul?ll={x},{y}"
},
- "Intel": {
+ {
+ "name": "Intel",
"url": "https://intel.ingress.com/intel?pll={x},{y}"
}
- },
+ ],
"icons": {
"Read_More_Here": "https://github.com/WatWowMap/ReactMap/wiki/Icons-Configuration",
"customizable": [],
@@ -606,5 +583,5 @@
"regional": [],
"event": []
},
- "manualAreas": {}
+ "manualAreas": []
}
\ No newline at end of file
diff --git a/server/src/configs/config.example.json b/server/src/configs/local.example.json
similarity index 54%
rename from server/src/configs/config.example.json
rename to server/src/configs/local.example.json
index 6fef4fdb3..b7fbb2f2a 100644
--- a/server/src/configs/config.example.json
+++ b/server/src/configs/local.example.json
@@ -2,55 +2,84 @@
"interface": "0.0.0.0",
"port": 8080,
"api": {
- "sessionSecret": "98ki^e72~!@#(85o3kXLI*#c9wu5l!Z",
+ "sessionSecret": "98ki^e72~!@#(85o3kXLI*#c9wu5l!Zx",
"reactMapSecret": "You Should Change Me",
"maxSessions": 5,
"queryAvailable": {
"pokemon": true,
- "quests": true,
- "raids": true,
- "nests": false
+ "quest": true,
+ "raid": true,
+ "nest": false
+ },
+ "pvp": {
+ "leagues": [
+ {
+ "name": "great",
+ "cp": 1500
+ },
+ {
+ "name": "ultra",
+ "cp": 2500
+ }
+ ],
+ "levels": [
+ 50,
+ 51
+ ],
+ "reactMapHandlesPvp": false
}
},
"map": {
- "title": "ReactMap",
- "headerTitle": "ReactMap",
- "nestHemisphere": "north",
- "style": "dark",
- "enableFeedback": true,
- "feedbackLink": "https://forms.gle/wKqWRs9Z7XEAPB7AA",
- "enableStats": true,
- "statsLink": "https://rdmopole2link.net",
- "startLat": 0,
- "startLon": 0,
- "startZoom": 12,
- "minZoom": 10,
- "maxZoom": 18,
- "enableQuestSetSelector": true
+ "general": {
+ "title": "ReactMap",
+ "headerTitle": "ReactMap",
+ "startLat": 0,
+ "startLon": 0,
+ "startZoom": 12,
+ "minZoom": 10,
+ "maxZoom": 18
+ },
+ "links": {
+ "feedbackLink": "",
+ "statsLink": ""
+ },
+ "misc": {
+ "enableQuestSetSelector": true
+ }
},
"clientSideOptions": {
"pokemon": {
"clustering": true,
"glow": [
- { "name": "Hundo", "perm": "iv", "num": 100, "value": "#ff1744", "op": "=" },
- { "name": "Top 3 Ranks", "perm": "pvp", "num": 3, "value": "#0000ff", "op": "<=" },
- { "name": "Multiple", "perm": "pvp", "value": "#800080" }
+ {
+ "name": "Hundo",
+ "perm": "iv",
+ "num": 100,
+ "value": "#ff1744",
+ "op": "="
+ },
+ {
+ "name": "Top 3 Ranks",
+ "perm": "pvp",
+ "num": 3,
+ "value": "#0000ff",
+ "op": "<="
+ },
+ {
+ "name": "Multiple",
+ "perm": "pvp",
+ "value": "#800080"
+ }
]
}
},
"database": {
"settings": {
"userTableName": "users",
- "sessionTableName": "session",
- "leagues": [
- { "name": "great", "cp": 1500 },
- { "name": "ultra", "cp": 2500 }
- ],
- "reactMapHandlesPvp": false,
- "pvpLevels": [50, 51]
+ "sessionTableName": "session"
},
- "schemas": {
- "scanner": {
+ "schemas": [
+ {
"type": "rdm/chuck/cdc/mad/manual",
"host": "127.0.0.1",
"port": 3306,
@@ -58,10 +87,18 @@
"password": "pass123!",
"database": "rdmdb",
"charset": "utf8mb4",
- "arScanColumn": false,
- "useFor": ["device", "gym", "pokemon", "pokestop", "s2cell", "spawnpoint", "weather"]
+ "hasAltQuests": false,
+ "useFor": [
+ "device",
+ "gym",
+ "pokemon",
+ "pokestop",
+ "scanCell",
+ "spawnpoint",
+ "weather"
+ ]
},
- "manual": {
+ {
"type": "manual",
"host": "127.0.0.1",
"port": 3306,
@@ -69,25 +106,33 @@
"password": "pass123!",
"database": "manual_1",
"charset": "utf8mb4",
- "arScanColumn": false,
- "useFor": ["session", "user", "nest", "portal"]
+ "useFor": [
+ "session",
+ "user",
+ "nest",
+ "portal"
+ ]
}
- }
+ ]
},
- "alwaysEnabledPerms": [],
- "discord": {
- "enabled": false,
- "logChannelId": "",
- "presence": "Map Status: Online",
- "presenceType": 3,
- "botToken": "",
- "clientId": "",
- "clientSecret": "",
- "redirectUri": "http://localhost:8080/auth/discord/callback",
- "inviteLink": "",
- "allowedGuilds": [],
- "blockedGuilds": [],
- "allowedUsers": [],
+ "authentication": {
+ "strategies": [
+ {
+ "enabled": false,
+ "type": "discord",
+ "name": "discord",
+ "logChannelId": "",
+ "presence": "Map Status: Online",
+ "presenceType": 3,
+ "botToken": "",
+ "clientId": "",
+ "clientSecret": "",
+ "redirectUri": "http://localhost:8080/auth/discord/callback",
+ "allowedGuilds": [],
+ "blockedGuilds": [],
+ "allowedUsers": []
+ }
+ ],
"areaRestrictions": [
{
"roles": [],
@@ -98,6 +143,7 @@
"areas": []
}
],
+ "alwaysEnabledPerms": [],
"perms": {
"map": {
"enabled": true,
@@ -107,10 +153,6 @@
"enabled": true,
"roles": []
},
- "stats": {
- "enabled": true,
- "roles": []
- },
"iv": {
"enabled": true,
"roles": []
@@ -167,28 +209,47 @@
"enabled": true,
"roles": []
},
- "s2cells": {
- "enabled": true,
+ "scanCells": {
"roles": []
},
"devices": {
"enabled": true,
"roles": []
+ },
+ "donor": {
+ "roles": []
}
}
},
- "tileServers": {
- "AlidadeSmoothDark": {
- "attribution": "© Stadia Maps, © OpenMapTiles © OpenStreetMap contributors",
- "url": "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png",
+ "tileServers": [
+ {
+ "name": "auto"
+ },
+ {
+ "name": "Carto",
+ "attribution": "Map tiles by Carto, under CC BY 3.0. Data by OpenStreetMap, under ODbL.",
+ "url": "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
+ "style": "light"
+ },
+ {
+ "name": "OSM",
+ "attribution": "Map data © OpenStreetMap contributors",
+ "url": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
+ "style": "light"
+ },
+ {
+ "name": "Dark Matter",
+ "attribution": "© OpenStreetMap contributors © CARTO",
+ "url": "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
"style": "dark"
},
- "ThunderForest": {
- "attribution": "© Thunderforest, © OpenStreetMap contributors",
- "url": "https://{s}.tile.thunderforest.com/transport-dark/{z}/{x}/{y}.png",
+ {
+ "name": "Satellite",
+ "attribution": "© Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community",
+ "url": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
"style": "dark"
}
- },
+ ],
"icons": {
"Read_More_Here": "https://github.com/WatWowMap/ReactMap/wiki/Icons-Configuration",
"customizable": [
@@ -250,15 +311,20 @@
}
]
},
- "manualAreas": {
- "New York": {
+ "manualAreas": [
+ {
+ "name": "New York",
"lat": 40.7481666,
- "lon": -74.0174788
+ "lon": -74.0174788,
+ "zoom": 15
},
- "San Francisco": {
+ {
+ "name": "San Francisco",
"lat": 37.79539194255634,
"lon": -122.39333173075096
},
- "Remove these if you'd prefer the map to read directly from your Geojson": ""
- }
+ {
+ "name": "Remove all of these if you'd prefer the map to read directly from your Geojson"
+ }
+ ]
}
\ No newline at end of file
diff --git a/server/src/db/initialization.js b/server/src/db/initialization.js
index f2a0f2fd3..0ed865181 100644
--- a/server/src/db/initialization.js
+++ b/server/src/db/initialization.js
@@ -1,11 +1,11 @@
/* eslint-disable no-console */
const Knex = require('knex')
-const { database: { schemas: { scanner, manual } } } = require('../configs/config.example.json')
+const { database: { schemas: exampleSchemas } } = require('../configs/local.example.json')
const { database: { schemas, settings }, devOptions: { queryDebug } } = require('../services/config')
const models = require('../models/index')
// Establishes knex connections to each database listed in the config
-const connections = Object.values(schemas).map(schema => Knex({
+const connections = schemas.map(schema => Knex({
client: 'mysql2',
connection: {
host: schema.host,
@@ -24,7 +24,7 @@ const connections = Object.values(schemas).map(schema => Knex({
}))
// Binds the models to the designated databases
-Object.values(schemas).forEach((schema, index) => {
+schemas.forEach((schema, index) => {
try {
schema.useFor.forEach(category => {
const capital = `${category.charAt(0).toUpperCase()}${category.slice(1)}`
@@ -32,7 +32,7 @@ Object.values(schemas).forEach((schema, index) => {
})
} catch (e) {
console.error(`
- Only ${[...scanner.useFor, ...manual.useFor].join(', ')} are valid options in the useFor fields`, '\n\n', e)
+ Only ${[exampleSchemas.flatMap(s => s.useFor)].join(', ')} are valid options in the useFor fields`, '\n\n', e)
process.exit(9)
}
})
diff --git a/server/src/graphql/resolvers.js b/server/src/graphql/resolvers.js
index 7e7658f28..7d7f352cc 100644
--- a/server/src/graphql/resolvers.js
+++ b/server/src/graphql/resolvers.js
@@ -1,15 +1,10 @@
/* eslint-disable no-console */
const GraphQLJSON = require('graphql-type-json')
-const fs = require('fs')
const { raw } = require('objection')
const config = require('../services/config')
-const scanAreas = fs.existsSync('server/src/configs/areas.json')
- // eslint-disable-next-line global-require
- ? require('../configs/areas.json')
- : { features: [] }
const {
- Device, Gym, Pokemon, Pokestop, Portal, S2cell, Spawnpoint, Weather, Nest, User,
+ Device, Gym, Pokemon, Pokestop, Portal, ScanCell, Spawnpoint, Weather, Nest, User,
} = require('../models/index')
const Utility = require('../services/Utility')
const Fetch = require('../services/Fetch')
@@ -20,7 +15,7 @@ module.exports = {
devices: (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
if (perms?.devices) {
- return Device.getAllDevices({ areaRestrictions: [] }, Utility.dbSelection('device') === 'mad')
+ return Device.getAllDevices({ areaRestrictions: [] }, Utility.dbSelection('device').type === 'mad')
}
return []
},
@@ -37,7 +32,7 @@ module.exports = {
gyms: (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
if (perms?.gyms || perms?.raids) {
- return Gym.getAllGyms(args, perms, Utility.dbSelection('gym') === 'mad')
+ return Gym.getAllGyms(args, perms, Utility.dbSelection('gym').type === 'mad')
}
return []
},
@@ -46,7 +41,7 @@ module.exports = {
if (perms?.[args.perm]) {
const query = Gym.query()
.findById(args.id)
- if (Utility.dbSelection('gym') === 'mad') {
+ if (Utility.dbSelection('gym').type === 'mad') {
query.select([
'latitude AS lat',
'longitude AS lon',
@@ -76,7 +71,7 @@ module.exports = {
|| perms?.lures
|| perms?.quests
|| perms?.invasions) {
- return Pokestop.getAllPokestops(args, perms, Utility.dbSelection('pokestop') === 'mad')
+ return Pokestop.getAllPokestops(args, perms, Utility.dbSelection('pokestop').type === 'mad')
}
return []
},
@@ -85,7 +80,7 @@ module.exports = {
if (perms?.[args.perm]) {
const query = Pokestop.query()
.findById(args.id)
- if (Utility.dbSelection('pokestop') === 'mad') {
+ if (Utility.dbSelection('pokestop').type === 'mad') {
query.select([
'latitude AS lat',
'longitude AS lon',
@@ -98,7 +93,7 @@ module.exports = {
pokemon: (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
if (perms?.pokemon) {
- const isMad = Utility.dbSelection('pokemon') === 'mad'
+ const isMad = Utility.dbSelection('pokemon').type === 'mad'
if (args.filters.onlyLegacy) {
return Pokemon.getLegacy(args, perms, isMad)
}
@@ -110,7 +105,7 @@ module.exports = {
const perms = req.user ? req.user.perms : req.session.perms
if (perms?.[args.perm]) {
const query = Pokemon.query().findById(args.id)
- if (Utility.dbSelection('pokemon') === 'mad') {
+ if (Utility.dbSelection('pokemon').type === 'mad') {
query.select([
'latitude AS lat',
'longitude AS lon',
@@ -134,29 +129,30 @@ module.exports = {
}
return {}
},
- s2cells: (parent, args, { req }) => {
+ scanCells: (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
- if (perms?.s2cells && args.zoom >= config.map.scanCellsZoom) {
- return S2cell.getAllCells(args, perms, Utility.dbSelection('pokestop') === 'mad')
+ if (perms?.scanCells && args.zoom >= config.map.scanCellsZoom) {
+ return ScanCell.getAllCells(args, perms, Utility.dbSelection('pokestop').type === 'mad')
}
return []
},
scanAreas: (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
- if (perms?.scanAreas && scanAreas.features.length) {
+ if (perms?.scanAreas && config.scanAreas.features.length) {
try {
- scanAreas.features = scanAreas.features.sort((a, b) => (a.properties.name > b.properties.name) ? 1 : -1)
+ config.scanAreas.features = config.scanAreas.features
+ .sort((a, b) => (a.properties.name > b.properties.name) ? 1 : -1)
} catch (e) {
console.warn('Failed to sort scan areas', e.message)
}
}
- return [scanAreas]
+ return [config.scanAreas]
},
search: async (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
const { category, webhookName } = args
if (perms?.[category]) {
- const isMad = Utility.dbSelection(category.substring(0, category.length - 1)) === 'mad'
+ const isMad = Utility.dbSelection(category.substring(0, category.length - 1)).type === 'mad'
const distance = raw(`ROUND(( 3959 * acos( cos( radians(${args.lat}) ) * cos( radians( ${isMad ? 'latitude' : 'lat'} ) ) * cos( radians( ${isMad ? 'longitude' : 'lon'} ) - radians(${args.lon}) ) + sin( radians(${args.lat}) ) * sin( radians( ${isMad ? 'latitude' : 'lat'} ) ) ) ),2)`).as('distance')
if (args.search === '') {
@@ -194,7 +190,7 @@ module.exports = {
const perms = req.user ? req.user.perms : req.session.perms
const { category } = args
if (perms?.[category]) {
- const isMad = Utility.dbSelection(category.substring(0, category.length - 1)) === 'mad'
+ const isMad = Utility.dbSelection(category.substring(0, category.length - 1)).type === 'mad'
const distance = raw(`ROUND(( 3959 * acos( cos( radians(${args.lat}) ) * cos( radians( ${isMad ? 'latitude' : 'lat'} ) ) * cos( radians( ${isMad ? 'longitude' : 'lon'} ) - radians(${args.lon}) ) + sin( radians(${args.lat}) ) * sin( radians( ${isMad ? 'latitude' : 'lat'} ) ) ) ),2)`).as('distance')
if (args.search === '') {
@@ -206,15 +202,15 @@ module.exports = {
spawnpoints: (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
if (perms?.spawnpoints) {
- return Spawnpoint.getAllSpawnpoints(args, perms, Utility.dbSelection('spawnpoint') === 'mad')
+ return Spawnpoint.getAllSpawnpoints(args, perms, Utility.dbSelection('spawnpoint').type === 'mad')
}
return []
},
submissionCells: async (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
if (perms?.submissionCells && args.zoom >= config.map.submissionZoom - 1) {
- const isMadStops = Utility.dbSelection('pokestop') === 'mad'
- const isMadGyms = Utility.dbSelection('gym') === 'mad'
+ const isMadStops = Utility.dbSelection('pokestop').type === 'mad'
+ const isMadGyms = Utility.dbSelection('gym').type === 'mad'
const stopQuery = Pokestop.query()
if (isMadStops) {
@@ -266,7 +262,7 @@ module.exports = {
weather: (parent, args, { req }) => {
const perms = req.user ? req.user.perms : req.session.perms
if (perms?.weather) {
- return Weather.getAllWeather(Utility.dbSelection('weather') === 'mad')
+ return Weather.getAllWeather(Utility.dbSelection('weather').type === 'mad')
}
return []
},
diff --git a/server/src/graphql/scannerTypes.js b/server/src/graphql/scannerTypes.js
index 409c5f910..5663a5882 100644
--- a/server/src/graphql/scannerTypes.js
+++ b/server/src/graphql/scannerTypes.js
@@ -159,7 +159,7 @@ module.exports = gql`
updated: Int
}
- type S2cell {
+ type ScanCell {
id: ID
level: Int
center_lat: Float
diff --git a/server/src/graphql/typeDefs.js b/server/src/graphql/typeDefs.js
index 2b5334f66..123fd344d 100644
--- a/server/src/graphql/typeDefs.js
+++ b/server/src/graphql/typeDefs.js
@@ -23,7 +23,7 @@ module.exports = gql`
pokemonSingle(id: ID, perm: String): Pokemon
portals(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON): [Portal]
portalsSingle(id: ID, perm: String): Portal
- s2cells(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON, zoom: Int): [S2cell]
+ scanCells(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON, zoom: Int): [ScanCell]
scanAreas: [ScanArea]
search(search: String, category: String, lat: Float, lon: Float, locale: String, webhookName: String, ts: Int, midnight: Int): [Search]
searchQuest(search: String, category: String, lat: Float, lon: Float, locale: String, webhookName: String, ts: Int, midnight: Int): [SearchQuest]
diff --git a/server/src/index.js b/server/src/index.js
index e9a92f871..dce5d7e0d 100644
--- a/server/src/index.js
+++ b/server/src/index.js
@@ -3,7 +3,6 @@
/* eslint-disable global-require */
const express = require('express')
const path = require('path')
-const fs = require('fs')
const logger = require('morgan')
const compression = require('compression')
const session = require('express-session')
@@ -14,10 +13,10 @@ const Backend = require('i18next-fs-backend')
const { ApolloServer } = require('apollo-server-express')
require('./db/initialization')
+const config = require('./services/config')
const { Pokemon } = require('./models/index')
const { sessionStore } = require('./services/sessionStore')
const rootRouter = require('./routes/rootRouter')
-const config = require('./services/config')
const typeDefs = require('./graphql/typeDefs')
const resolvers = require('./graphql/resolvers')
@@ -88,17 +87,13 @@ app.use(session({
cookie: { maxAge: 604800000 },
}))
-fs.readdir(`${__dirname}/strategies/`, (e, files) => {
- if (e) return console.error(e)
- files.forEach(file => {
- const trimmed = file.replace('.js', '')
- if (config[trimmed]?.enabled) {
- require(`./strategies/${trimmed}`)
- console.log(file, 'strategy initialized')
- } else {
- console.log(file, 'strategy not enabled, if this was a mistake, make sure to add it to the config and enable it')
- }
- })
+config.authentication.strategies.forEach(strategy => {
+ if (strategy.enabled) {
+ require(`./strategies/${strategy.name}.js`)
+ console.log(`Strategy ${strategy.name} initialized`)
+ } else {
+ console.log(`Strategy ${strategy.name} was not initialized`)
+ }
})
app.use(passport.initialize())
@@ -120,7 +115,7 @@ passport.deserializeUser(async (user, done) => {
i18next.use(Backend).init({
lng: 'en',
fallbackLng: 'en',
- preload: config.localeSelection,
+ preload: config.map.localeSelection,
ns: ['translation'],
defaultNS: 'translation',
backend: { loadPath: 'public/locales/{{lng}}/{{ns}}.json' },
@@ -143,7 +138,7 @@ app.use((err, req, res, next) => {
}
})
-if (config.database.settings.reactMapHandlesPvp) {
+if (config.api.pvp.reactMapHandlesPvp) {
(async () => Pokemon.initOhbem())()
}
diff --git a/server/src/models/Device.js b/server/src/models/Device.js
index 280edffa0..855ae4d3f 100644
--- a/server/src/models/Device.js
+++ b/server/src/models/Device.js
@@ -2,13 +2,13 @@ const { Model, raw } = require('objection')
const dbSelection = require('../services/functions/dbSelection')
const getAreaSql = require('../services/functions/getAreaSql')
-class Device extends Model {
+module.exports = class Device extends Model {
static get tableName() {
- return dbSelection('device') === 'mad' ? 'settings_device' : 'device'
+ return dbSelection('device').type === 'mad' ? 'settings_device' : 'device'
}
static get idColumn() {
- return dbSelection('device') === 'mad' ? 'device_id' : 'uuid'
+ return dbSelection('device').type === 'mad' ? 'device_id' : 'uuid'
}
static async getAllDevices(perms, isMad) {
@@ -42,5 +42,3 @@ class Device extends Model {
return query
}
}
-
-module.exports = Device
diff --git a/server/src/models/Filters.js b/server/src/models/Filters.js
index b987dfb3e..0d4c6e990 100644
--- a/server/src/models/Filters.js
+++ b/server/src/models/Filters.js
@@ -1,5 +1,5 @@
/* eslint-disable max-classes-per-file */
-const { database: { settings: { leagues } } } = require('../services/config')
+const { api: { pvp: { leagues } } } = require('../services/config')
class GenericFilter {
constructor(enabled, size) {
@@ -9,7 +9,7 @@ class GenericFilter {
}
class PokemonFilter extends GenericFilter {
- constructor(iv, level, atk, def, sta, enabled, size) {
+ constructor(iv, level, atk, def, sta, pvp, enabled, size) {
super(enabled, size)
this.iv = iv || [0, 100]
this.atk_iv = atk || [0, 15]
@@ -17,10 +17,7 @@ class PokemonFilter extends GenericFilter {
this.sta_iv = sta || [0, 15]
this.level = level || [1, 35]
this.adv = ''
- }
-
- pvp(values) {
- leagues.forEach(league => this[league.name] = values || [(league.minRank || 1), (league.maxRank || 100)])
+ leagues.forEach(league => this[league.name] = pvp || [(league.minRank || 1), (league.maxRank || 100)])
}
}
diff --git a/server/src/models/Gym.js b/server/src/models/Gym.js
index 277f0f732..3b65a9eed 100644
--- a/server/src/models/Gym.js
+++ b/server/src/models/Gym.js
@@ -7,13 +7,13 @@ const dbSelection = require('../services/functions/dbSelection')
const getAreaSql = require('../services/functions/getAreaSql')
const { api: { searchResultsLimit } } = require('../services/config')
-class Gym extends Model {
+module.exports = class Gym extends Model {
static get tableName() {
return 'gym'
}
static get idColumn() {
- return dbSelection('gym') === 'mad'
+ return dbSelection('gym').type === 'mad'
? 'gym_id' : 'id'
}
@@ -286,5 +286,3 @@ class Gym extends Model {
return query
}
}
-
-module.exports = Gym
diff --git a/server/src/models/Nest.js b/server/src/models/Nest.js
index afd58a168..c51c4623c 100644
--- a/server/src/models/Nest.js
+++ b/server/src/models/Nest.js
@@ -5,7 +5,7 @@ const getAreaSql = require('../services/functions/getAreaSql')
const { pokemon: masterPkmn } = require('../data/masterfile.json')
const { api: { searchResultsLimit } } = require('../services/config')
-class Nest extends Model {
+module.exports = class Nest extends Model {
static get tableName() {
return 'nests'
}
@@ -85,5 +85,3 @@ class Nest extends Model {
return query
}
}
-
-module.exports = Nest
diff --git a/server/src/models/Pokemon.js b/server/src/models/Pokemon.js
index aefcef54d..2cb3814fd 100644
--- a/server/src/models/Pokemon.js
+++ b/server/src/models/Pokemon.js
@@ -4,15 +4,12 @@ const Ohbem = require('ohbem')
const { pokemon: masterfile } = require('../data/masterfile.json')
const legacyFilter = require('../services/legacyFilter')
const {
- api: { pvpMinCp },
- database: {
- settings: { leagues, reactMapHandlesPvp, pvpLevels },
- },
+ api: { pvp: { minCp: pvpMinCp, leagues, reactMapHandlesPvp, levels } },
} = require('../services/config')
const dbSelection = require('../services/functions/dbSelection')
const getAreaSql = require('../services/functions/getAreaSql')
-const dbType = dbSelection('pokemon')
+const { type: dbType } = dbSelection('pokemon')
const levelCalc = 'IFNULL(IF(cp_multiplier < 0.734, ROUND(58.35178527 * cp_multiplier * cp_multiplier - 2.838007664 * cp_multiplier + 0.8539209906), ROUND(171.0112688 * cp_multiplier - 95.20425243)), NULL)'
const ivCalc = 'IFNULL((individual_attack + individual_defense + individual_stamina) / 0.45, NULL)'
const keys = ['iv', 'level', 'atk_iv', 'def_iv', 'sta_iv', ...leagues.map(league => league.name)]
@@ -58,13 +55,13 @@ const getMadSql = q => (
])
)
-class Pokemon extends Model {
+module.exports = class Pokemon extends Model {
static get tableName() {
return 'pokemon'
}
static get idColumn() {
- return dbSelection('pokemon') === 'mad'
+ return dbSelection('pokemon').type === 'mad'
? 'encounter_id' : 'id'
}
@@ -77,14 +74,14 @@ class Pokemon extends Model {
ohbem = new Ohbem({
leagues: leagueObj,
pokemonData: await Ohbem.fetchPokemonData(),
- levelCaps: pvpLevels,
+ levelCaps: levels,
cachingStrategy: Ohbem.cachingStrategies.memoryHeavy,
})
}
static async getPokemon(args, perms, isMad) {
const {
- stats, iv: ivs, pvp, areaRestrictions,
+ iv: ivs, pvp, areaRestrictions,
} = perms
const {
onlyStandard, onlyIvOr, onlyXlKarp, onlyXsRat, onlyZeroIv, onlyHundoIv, onlyPvpMega, onlyLinkGlobal, ts,
@@ -93,7 +90,7 @@ class Pokemon extends Model {
const safeTs = ts || Math.floor((new Date()).getTime() / 1000)
// quick check to make sure no Pokemon are returned when none are enabled for users with only Pokemon perms
- if (!ivs && !stats && !pvp) {
+ if (!ivs && !pvp) {
const noPokemonSelect = Object.keys(args.filters).find(x => x.charAt(0) !== 'o')
if (!noPokemonSelect) return []
}
@@ -184,15 +181,12 @@ class Pokemon extends Model {
queryBase.whereNull('pokemon_id')
}
} break
- case 'iv':
- if (ivs) {
- queryBase.andWhereBetween(isMad ? madKeys[key] : key, filter[key])
- } break
case 'level':
case 'atk_iv':
case 'def_iv':
case 'sta_iv':
- if (stats) {
+ case 'iv':
+ if (ivs) {
queryBase.andWhereBetween(isMad ? madKeys[key] : key, filter[key])
} break
}
@@ -236,7 +230,7 @@ class Pokemon extends Model {
generateSql(poke, filter, relevantFilters, true)
}
})
- } else if (pkmn === 'onlyIvOr' && (ivs || stats || pvp)) {
+ } else if (pkmn === 'onlyIvOr' && (ivs || pvp)) {
const relevantFilters = getRelevantKeys(filter)
if (relevantFilters.length > 0) {
generateSql(ivOr, filter, relevantFilters)
@@ -397,5 +391,3 @@ class Pokemon extends Model {
return results.map(pkmn => `${pkmn.pokemon_id}-${pkmn.form}`)
}
}
-
-module.exports = Pokemon
diff --git a/server/src/models/Pokestop.js b/server/src/models/Pokestop.js
index e67be82a5..3274bf020 100644
--- a/server/src/models/Pokestop.js
+++ b/server/src/models/Pokestop.js
@@ -5,7 +5,11 @@ const { pokemon: masterPkmn, items: masterItems, questRewardTypes } = require('.
const fetchQuests = require('../services/api/fetchQuests')
const dbSelection = require('../services/functions/dbSelection')
const getAreaSql = require('../services/functions/getAreaSql')
-const { api: { searchResultsLimit }, database: { schemas, settings }, map } = require('../services/config')
+const {
+ api: { searchResultsLimit },
+ database: { settings },
+ map,
+} = require('../services/config')
const questProps = {
quest_type: true,
@@ -36,11 +40,10 @@ const invasionProps = {
incident_expire_timestamp: true,
grunt_type: true,
}
-const dbType = dbSelection('pokestop')
-const { hasAltQuests } = Object.values(schemas).find(schema => schema.useFor.includes('pokestop'))
-const altQuestCheck = hasAltQuests && dbType !== 'mad'
+const { type, hasAltQuests } = dbSelection('pokestop')
+const altQuestCheck = hasAltQuests && type !== 'mad'
-class Pokestop extends Model {
+module.exports = class Pokestop extends Model {
static get tableName() {
return 'pokestop'
}
@@ -90,7 +93,7 @@ class Pokestop extends Model {
.as('incident_expire_timestamp'),
])
}
- if (dbType === 'chuck') {
+ if (type === 'chuck') {
query.join('incident', 'pokestop.id', 'incident.pokestop_id')
.select([
'*',
@@ -226,7 +229,7 @@ class Pokestop extends Model {
})
}
if (onlyInvasions && invasionPerms) {
- if (dbType === 'chuck') {
+ if (type === 'chuck') {
stops.orWhere(invasion => {
invasion.whereIn('character', invasions)
.andWhere('expiration_ms', '>=', safeTs * 1000)
@@ -506,8 +509,8 @@ class Pokestop extends Model {
}
}
- Object.entries(quests).forEach(([type, rewards]) => {
- switch (type) {
+ Object.entries(quests).forEach(([questType, rewards]) => {
+ switch (questType) {
case 'items': rewards.forEach(reward => finalList.add(`q${reward.quest_item_id}`)); break
case 'mega': rewards.forEach(reward => finalList.add(`m${reward.id}-${reward.amount}`)); break
case 'invasions': rewards.forEach(reward => finalList.add(`i${reward.grunt_type}`)); break
@@ -534,8 +537,8 @@ class Pokestop extends Model {
.orderBy(isMad ? 'active_fort_modifier' : 'lure_id')
Object.entries(stops).forEach(stopType => {
- const [type, rewards] = stopType
- switch (type) {
+ const [sType, rewards] = stopType
+ switch (sType) {
default: rewards.forEach(reward => finalList.add(`i${reward.grunt_type}`)); break
case 'lures': rewards.forEach(reward => finalList.add(`l${reward.lure_id}`)); break
}
@@ -605,8 +608,8 @@ class Pokestop extends Model {
const itemIds = Object.keys(masterItems).filter(item => (
i18next.t(`item_${item}`, { lng: locale }).toLowerCase().includes(search)
))
- const rewardTypes = Object.keys(questRewardTypes).filter(type => (
- i18next.t(`quest_reward_${type}`, { lng: locale }).toLowerCase().includes(search)
+ const rewardTypes = Object.keys(questRewardTypes).filter(rType => (
+ i18next.t(`quest_reward_${rType}`, { lng: locale }).toLowerCase().includes(search)
))
const query = this.query()
@@ -679,5 +682,3 @@ class Pokestop extends Model {
return results.map(result => isMad ? this.parseMadRewards(result) : this.parseRdmRewards(result)).filter(x => x)
}
}
-
-module.exports = Pokestop
diff --git a/server/src/models/Portal.js b/server/src/models/Portal.js
index 9f61ee2c2..279fffe78 100644
--- a/server/src/models/Portal.js
+++ b/server/src/models/Portal.js
@@ -1,8 +1,10 @@
const { Model } = require('objection')
const getAreaSql = require('../services/functions/getAreaSql')
-const { api: { searchResultsLimit, portalUpdateLimit } } = require('../services/config')
+const {
+ api: { searchResultsLimit, portalUpdateLimit },
+} = require('../services/config')
-class Portal extends Model {
+module.exports = class Portal extends Model {
static get tableName() {
return 'ingress_portals'
}
@@ -40,5 +42,3 @@ class Portal extends Model {
return query
}
}
-
-module.exports = Portal
diff --git a/server/src/models/Ring.js b/server/src/models/Ring.js
index ee41c6511..2ec31c31c 100644
--- a/server/src/models/Ring.js
+++ b/server/src/models/Ring.js
@@ -1,9 +1,7 @@
-class Ring {
+module.exports = class Ring {
constructor(id, lat, lon) {
this.id = id
this.lat = lat
this.lon = lon
}
}
-
-module.exports = Ring
diff --git a/server/src/models/S2cell.js b/server/src/models/ScanCell.js
similarity index 90%
rename from server/src/models/S2cell.js
rename to server/src/models/ScanCell.js
index ab33baef1..7315d6503 100644
--- a/server/src/models/S2cell.js
+++ b/server/src/models/ScanCell.js
@@ -3,9 +3,9 @@ const dbSelection = require('../services/functions/dbSelection')
const getPolyVector = require('../services/functions/getPolyVector')
const getAreaSql = require('../services/functions/getAreaSql')
-class S2cell extends Model {
+module.exports = class ScanCell extends Model {
static get tableName() {
- return dbSelection('s2cell') === 'mad'
+ return dbSelection('scanCell').type === 'mad'
? 'trs_s2cells' : 's2cell'
}
@@ -27,5 +27,3 @@ class S2cell extends Model {
}))
}
}
-
-module.exports = S2cell
diff --git a/server/src/models/Session.js b/server/src/models/Session.js
index 7884186ef..0af86b7a9 100644
--- a/server/src/models/Session.js
+++ b/server/src/models/Session.js
@@ -1,10 +1,8 @@
const { Model } = require('objection')
const { database: { settings: { sessionTableName } } } = require('../services/config')
-class Session extends Model {
+module.exports = class Session extends Model {
static get tableName() {
return sessionTableName
}
}
-
-module.exports = Session
diff --git a/server/src/models/Spawnpoint.js b/server/src/models/Spawnpoint.js
index 350f93509..adc68b56c 100644
--- a/server/src/models/Spawnpoint.js
+++ b/server/src/models/Spawnpoint.js
@@ -2,14 +2,14 @@ const { Model, raw } = require('objection')
const dbSelection = require('../services/functions/dbSelection')
const getAreaSql = require('../services/functions/getAreaSql')
-class Spawnpoint extends Model {
+module.exports = class Spawnpoint extends Model {
static get tableName() {
- return dbSelection('spawnpoint') === 'mad'
+ return dbSelection('spawnpoint').type === 'mad'
? 'trs_spawn' : 'spawnpoint'
}
static get idColumn() {
- return dbSelection('spawnpoint') === 'mad'
+ return dbSelection('spawnpoint').type === 'mad'
? 'spawnpoint' : 'id'
}
@@ -35,5 +35,3 @@ class Spawnpoint extends Model {
return query
}
}
-
-module.exports = Spawnpoint
diff --git a/server/src/models/User.js b/server/src/models/User.js
index 2bde1dcc6..5efb81d89 100644
--- a/server/src/models/User.js
+++ b/server/src/models/User.js
@@ -2,7 +2,7 @@
const { Model } = require('objection')
const { database: { settings: { userTableName } } } = require('../services/config')
-class User extends Model {
+module.exports = class User extends Model {
static get tableName() {
return userTableName
}
@@ -14,5 +14,3 @@ class User extends Model {
.then(() => console.log(`[${botName}] Cleared ${strategy} perms for user ${userId}`))
}
}
-
-module.exports = User
diff --git a/server/src/models/Weather.js b/server/src/models/Weather.js
index ccc728a73..ad1f57ba4 100644
--- a/server/src/models/Weather.js
+++ b/server/src/models/Weather.js
@@ -3,13 +3,13 @@ const getPolyVector = require('../services/functions/getPolyVector')
const dbSelection = require('../services/functions/dbSelection')
const { api: { weatherCellLimit } } = require('../services/config')
-class Weather extends Model {
+module.exports = class Weather extends Model {
static get tableName() {
return 'weather'
}
static get idColumn() {
- return dbSelection('weather') === 'mad'
+ return dbSelection('weather').type === 'mad'
? 's2_cell_id' : 'id'
}
@@ -39,5 +39,3 @@ class Weather extends Model {
}))
}
}
-
-module.exports = Weather
diff --git a/server/src/models/index.js b/server/src/models/index.js
index bd0a43c73..4e59eb07f 100644
--- a/server/src/models/index.js
+++ b/server/src/models/index.js
@@ -5,7 +5,7 @@ const Pokestop = require('./Pokestop')
const Pokemon = require('./Pokemon')
const Portal = require('./Portal')
const Ring = require('./Ring')
-const S2cell = require('./S2cell')
+const ScanCell = require('./ScanCell')
const Session = require('./Session')
const Spawnpoint = require('./Spawnpoint')
const User = require('./User')
@@ -20,7 +20,7 @@ module.exports = {
Pokemon,
Portal,
Ring,
- S2cell,
+ ScanCell,
Session,
Spawnpoint,
User,
diff --git a/server/src/routes/authRouter.js b/server/src/routes/authRouter.js
index e7bcb4935..49b180a20 100644
--- a/server/src/routes/authRouter.js
+++ b/server/src/routes/authRouter.js
@@ -1,24 +1,22 @@
/* eslint-disable global-require */
/* eslint-disable import/no-dynamic-require */
/* eslint-disable no-console */
-const fs = require('fs')
const router = require('express').Router()
const passport = require('passport')
const { isValidSession, clearOtherSessions } = require('../services/sessionStore')
+const { authentication: { strategies } } = require('../services/config')
// Loads up the base auth routes and any custom ones
-fs.readdir(`${__dirname}/../strategies/`, (e, files) => {
- if (e) return console.error(e)
- files.forEach((file) => {
- const trimmed = file.replace('.js', '')
- const method = trimmed.includes('local') ? 'post' : 'get'
- router[method](`/${trimmed}`, passport.authenticate(trimmed, {
+strategies.forEach(strategy => {
+ const method = strategy.type === 'local' ? 'post' : 'get'
+ if (strategy.enabled) {
+ router[method](`/${strategy.name}`, passport.authenticate(strategy.name, {
successRedirect: '/',
failureMessage: true,
}))
- router[method](`/${trimmed}/callback`,
- async (req, res, next) => passport.authenticate(trimmed, async (err, user, info) => {
+ router[method](`/${strategy.name}/callback`,
+ async (req, res, next) => passport.authenticate(strategy.name, async (err, user, info) => {
if (err) { return next(err) }
if (!user) {
res.status(401).json(info.message)
@@ -38,8 +36,8 @@ fs.readdir(`${__dirname}/../strategies/`, (e, files) => {
}
}
})(req, res, next))
- console.log(`${method.toUpperCase()} /auth/${trimmed}/callback route initialized`)
- })
+ console.log(`${method.toUpperCase()} /auth/${strategy.name}/callback route initialized`)
+ }
})
module.exports = router
diff --git a/server/src/routes/clientRouter.js b/server/src/routes/clientRouter.js
index f0d86a6d7..ee40637f5 100644
--- a/server/src/routes/clientRouter.js
+++ b/server/src/routes/clientRouter.js
@@ -1,6 +1,6 @@
const express = require('express')
const path = require('path')
-const config = require('../services/config')
+const { devOptions } = require('../services/config')
const router = new express.Router()
@@ -15,7 +15,7 @@ const clientRoutes = [
]
router.get(clientRoutes, (req, res) => {
- res.sendFile(path.join(__dirname, `../${config.devOptions.clientPath}/index.html`))
+ res.sendFile(path.join(__dirname, `../${devOptions.clientPath}/index.html`))
})
module.exports = router
diff --git a/server/src/routes/rootRouter.js b/server/src/routes/rootRouter.js
index d20bd5c06..33321df0a 100644
--- a/server/src/routes/rootRouter.js
+++ b/server/src/routes/rootRouter.js
@@ -1,6 +1,5 @@
/* eslint-disable no-console */
const express = require('express')
-const fs = require('fs')
const { default: center } = require('@turf/center')
const authRouter = require('./authRouter')
@@ -30,18 +29,18 @@ rootRouter.get('/logout', (req, res) => {
rootRouter.get('/area/:area/:zoom?', (req, res) => {
const { area, zoom } = req.params
try {
- const scanAreas = fs.existsSync('server/src/configs/areas.json')
- // eslint-disable-next-line global-require
- ? require('../configs/areas.json')
- : { features: [] }
+ const { scanAreas, manualAreas } = config
if (scanAreas.features.length) {
const foundArea = scanAreas.features.find(a => a.properties.name.toLowerCase() === area.toLowerCase())
if (foundArea) {
const [lon, lat] = center(foundArea).geometry.coordinates
- res.redirect(`/@/${lat}/${lon}/${zoom || 15}`)
- } else {
- res.redirect('/404')
+ return res.redirect(`/@/${lat}/${lon}/${zoom || 18}`)
}
+ if (manualAreas.length) {
+ const { lat, lon } = manualAreas.find(a => a.name.toLowerCase() === area.toLowerCase())
+ return res.redirect(`/@/${lat}/${lon}/${zoom || 18}`)
+ }
+ return res.redirect('/404')
}
} catch (e) {
console.error(`Error navigating to ${area}`, e.message)
@@ -51,13 +50,13 @@ rootRouter.get('/area/:area/:zoom?', (req, res) => {
rootRouter.get('/settings', async (req, res) => {
try {
- if (!config.authMethods.length || config.alwaysEnabledPerms.length) {
+ if (!config.authMethods.length || config.authentication.alwaysEnabledPerms.length) {
req.session.perms = { areaRestrictions: [], webhooks: [] }
req.session.save()
}
- if (config.alwaysEnabledPerms.length) {
- config.alwaysEnabledPerms.forEach(perm => {
- if (config.discord.perms[perm]) {
+ if (config.authentication.alwaysEnabledPerms.length) {
+ config.authentication.alwaysEnabledPerms.forEach(perm => {
+ if (config.authentication.perms[perm]) {
req.session.perms[perm] = true
} else {
console.warn('Invalid Perm in "alwaysEnabledPerms" array:', perm)
@@ -94,12 +93,12 @@ rootRouter.get('/settings', async (req, res) => {
config: {
map: {
...config.map,
- ...config.multiDomains[req.headers.host],
- excludeList: config.excludeFromTutorial,
+ ...config.multiDomainsObj[req.headers.host],
+ excludeList: config.authentication.excludeFromTutorial,
},
- localeSelection: Object.fromEntries(config.localeSelection.map(locale => [locale, { name: locale }])),
- tileServers: { auto: {}, ...config.tileServers },
- navigation: config.navigation,
+ localeSelection: Object.fromEntries(config.map.localeSelection.map(l => [l, { name: l }])),
+ tileServers: Object.fromEntries(config.tileServers.map(s => [s.name, s])),
+ navigation: Object.fromEntries(config.navigation.map(n => [n.name, n])),
drawer: {
temporary: {},
persistent: {},
@@ -111,6 +110,12 @@ rootRouter.get('/settings', async (req, res) => {
manualAreas: config.manualAreas || {},
icons: config.icons,
},
+ available: {
+ pokemon: [],
+ pokestops: [],
+ gyms: [],
+ nests: [],
+ },
}
// add user options here from the config that are structured as objects
@@ -121,32 +126,29 @@ rootRouter.get('/settings', async (req, res) => {
const ignoreKeys = ['map', 'manualAreas', 'limit', 'icons']
Object.keys(serverSettings.config).forEach(setting => {
- if (!ignoreKeys.includes(setting)) {
- const category = serverSettings.config[setting]
- Object.keys(category).forEach(option => {
- category[option].name = option
- })
- if (config.map[setting] && typeof config.map[setting] !== 'object') {
- serverSettings.settings[setting] = config.map[setting]
- } else {
- serverSettings.settings[setting] = category[Object.keys(category)[0]].name
+ try {
+ if (!ignoreKeys.includes(setting)) {
+ const category = serverSettings.config[setting]
+ Object.keys(category).forEach(option => {
+ category[option].name = option
+ })
+ if (config.map[setting] && typeof config.map[setting] !== 'object') {
+ serverSettings.settings[setting] = config.map[setting]
+ } else {
+ serverSettings.settings[setting] = category[Object.keys(category)[0]].name
+ }
}
+ } catch (e) {
+ console.warn(`Error setting ${setting}, most likely means there are no options set in the config`, e.message)
}
})
serverSettings.defaultFilters = Utility.buildDefaultFilters(serverSettings.user.perms)
- serverSettings.available = {
- pokemon: [],
- pokestops: [],
- gyms: [],
- nests: [],
- }
-
try {
if (serverSettings.user.perms.pokemon) {
serverSettings.available.pokemon = config.api.queryAvailable.pokemon
- ? await Pokemon.getAvailablePokemon(Utility.dbSelection('pokemon') === 'mad')
+ ? await Pokemon.getAvailablePokemon(Utility.dbSelection('pokemon').type === 'mad')
: []
}
} catch (e) {
@@ -155,7 +157,7 @@ rootRouter.get('/settings', async (req, res) => {
try {
if (serverSettings.user.perms.raids || serverSettings.user.perms.gyms) {
serverSettings.available.gyms = config.api.queryAvailable.raids
- ? await Gym.getAvailableRaidBosses(Utility.dbSelection('gym') === 'mad')
+ ? await Gym.getAvailableRaidBosses(Utility.dbSelection('gym').type === 'mad')
: await Fetch.fetchRaids()
}
} catch (e) {
@@ -167,7 +169,7 @@ rootRouter.get('/settings', async (req, res) => {
|| serverSettings.user.perms.invasions
|| serverSettings.user.perms.lures) {
serverSettings.available.pokestops = config.api.queryAvailable.quests
- ? await Pokestop.getAvailableQuests(Utility.dbSelection('pokestop') === 'mad')
+ ? await Pokestop.getAvailableQuests(Utility.dbSelection('pokestop').type === 'mad')
: await Fetch.fetchQuests()
}
} catch (e) {
@@ -252,7 +254,7 @@ rootRouter.get('/settings', async (req, res) => {
.sort((a, b) => a.name.localeCompare(b.name))
.filter(area => area.userSelectable !== false)
.map(area => area.name),
- templates: config.webhookObj[webhook.name].client.templates[strategy],
+ templates: config.webhookObj[webhook.name].client.templates[webhookStrategy || strategy],
}
}
}
diff --git a/server/src/services/DiscordClient.js b/server/src/services/DiscordClient.js
index 052612260..41929697e 100644
--- a/server/src/services/DiscordClient.js
+++ b/server/src/services/DiscordClient.js
@@ -6,7 +6,7 @@
/* eslint-disable import/no-dynamic-require */
/* global BigInt */
const fs = require('fs')
-const { alwaysEnabledPerms, webhooks } = require('./config')
+const { authentication: { alwaysEnabledPerms }, webhooks } = require('./config')
const Utility = require('./Utility')
module.exports = class DiscordMapClient {
diff --git a/server/src/services/api/fetchNests.js b/server/src/services/api/fetchNests.js
index a78e87ca8..da481cff3 100644
--- a/server/src/services/api/fetchNests.js
+++ b/server/src/services/api/fetchNests.js
@@ -1,5 +1,5 @@
const fetchJson = require('./fetchJson')
-const { map: { nestHemisphere } } = require('../config')
+const { api: { nestHemisphere } } = require('../config')
const { pokemon: masterfile } = require('../../data/masterfile.json')
module.exports = async function fetchNests() {
diff --git a/server/src/services/api/resolveQuickHook.js b/server/src/services/api/resolveQuickHook.js
index afad5a1ca..0c388ec96 100644
--- a/server/src/services/api/resolveQuickHook.js
+++ b/server/src/services/api/resolveQuickHook.js
@@ -2,14 +2,6 @@
const fetchJson = require('./fetchJson')
const config = require('../config')
-// const looper = (num, toLoop, staticData, skipZero) => {
-// const arr = []
-// for (let i = skipZero ? 1 : 0; i <= num; i += 1) {
-// arr.push({ ...staticData, [toLoop]: i })
-// }
-// return arr
-// }
-
const getWildCards = (category) => {
switch (category) {
case 'gym': return { team: 4, slot_changes: true, battle_changes: true }
diff --git a/server/src/services/areas.js b/server/src/services/areas.js
index 286c9ac74..58e76e6bc 100644
--- a/server/src/services/areas.js
+++ b/server/src/services/areas.js
@@ -1,20 +1,15 @@
+/* eslint-disable no-console */
/* eslint-disable no-restricted-syntax */
-const fs = require('fs')
-const path = require('path')
-const {
- discord: { areaRestrictions: discord },
- telegram: { areaRestrictions: telegram },
-} = require('./config')
+const config = require('./config')
const loadAreas = () => {
let areas = {}
- const areasFilePath = path.resolve(__dirname, '../configs/areas.json')
try {
// eslint-disable-next-line global-require
- const data = fs.existsSync(areasFilePath, 'utf8') ? require('../configs/areas.json') : Error('Areas file not found')
+ const data = config.scanAreas || Error('Areas file not found')
areas = data
} catch (err) {
- const showWarning = discord.some(rule => rule.roles.length) || telegram.some(rule => rule.roles.length)
+ const showWarning = config.authentication.areaRestrictions.some(rule => rule.roles.length)
if (showWarning) {
console.warn('[Area Restrictions] Disabled - `areas.json` file is missing or broken.')
}
diff --git a/server/src/services/config.js b/server/src/services/config.js
index 0663a9b05..2ba7de429 100644
--- a/server/src/services/config.js
+++ b/server/src/services/config.js
@@ -1,58 +1,61 @@
+/* eslint-disable global-require */
/* eslint-disable no-console */
-const extend = require('extend')
+process.env.NODE_CONFIG_DIR = `${__dirname}/../configs`
+
const fs = require('fs')
-const uConfig = require('../configs/config.json')
-const eConfig = require('../configs/default.json')
-const initWebhooks = require('./initWebhooks')
+const config = require('config')
-const target = {}
-
-extend(true, target, eConfig, uConfig)
-
-try {
- target.authMethods = []
- fs.readdir(`${__dirname}/../strategies/`, (e, files) => {
- if (e) return console.error(e)
- files.forEach(file => {
- const trimmed = file.replace('.js', '')
- if (target[trimmed]?.enabled) {
- target.authMethods.push(trimmed)
- }
- })
- })
-} catch (e) {
- console.error('Failed to initialize a strategy', e)
+if (!fs.existsSync(`${__dirname}/../configs/local.json`)) {
+ console.log('Config v2 (local.json) not found, you need to run the migration with "yarn config-migrate"')
+ process.exit(1)
}
-if (target.map.messageOfTheDay.messages) {
- console.warn('You are using an old API endpoint in the message of the day section, the [messages] array should be renamed to [components]! \n They have been migrated for you in the meantime but you should update your config.json file.')
-
- const updateFieldRec = (messages) => messages.map(message => {
- if (message.messages) {
- message.components = updateFieldRec(message.messages)
- delete message.messages
- }
- return message
- })
-
- target.map.messageOfTheDay.components = target.map.messageOfTheDay.messages.map(m => {
- if (m.type !== 'parent') return m
- if (m.messages) {
- m.components = m.components || updateFieldRec(m.messages)
- delete m.messages
- }
- return m
- })
- delete target.map.messageOfTheDay.messages
-}
+const initWebhooks = require('./initWebhooks')
-if (target.icons.defaultIcons.misc) {
- console.warn('Warning: Setting the misc category to anything does not have an impact on the icons.')
-}
-if (target.webhooks.length) {
+const mergeMapConfig = (obj) => ({
+ localeSelection: obj.localeSelection,
+ ...obj,
+ ...obj.general,
+ ...obj.customRoutes,
+ ...obj.links,
+ ...obj.holidayEffects,
+ ...obj.misc,
+ general: undefined,
+ customRoutes: undefined,
+ links: undefined,
+ holidayEffects: undefined,
+ misc: undefined,
+})
+
+config.map = mergeMapConfig(config.map)
+
+config.multiDomainsObj = Object.fromEntries(
+ config.multiDomains.map(d => [d.domain, mergeMapConfig(d)]),
+)
+
+config.authMethods = []
+config.authentication.strategies.forEach(strategy => {
+ if (strategy.enabled) {
+ config.authentication[strategy.name] = strategy
+ config.authMethods.push(strategy.name)
+ }
+})
+
+config.map.noScanAreaOverlay = Boolean(config.manualAreas.length)
+
+if (config.webhooks.length) {
(async () => {
- target.webhookObj = await initWebhooks(target)
+ config.webhookObj = await initWebhooks(config)
})()
}
+['tileServers', 'navigation'].forEach(opt => {
+ if (!config[opt].length) console.warn(`[${opt}] is empty, you need to add options to it or remove the empty array from your config.`)
+})
+
+config.scanAreas = fs.existsSync(`${__dirname}/../configs/areas.json`)
+ ? require('../configs/areas.json')
+ : { features: [] }
+
+config.manualAreas = Object.fromEntries(config.manualAreas.map(area => [area.name, area]))
-module.exports = target
+module.exports = config
diff --git a/server/src/services/defaultFilters/buildDefaultFilters.js b/server/src/services/defaultFilters/buildDefaultFilters.js
index 97c146c0f..35d7af63a 100644
--- a/server/src/services/defaultFilters/buildDefaultFilters.js
+++ b/server/src/services/defaultFilters/buildDefaultFilters.js
@@ -1,21 +1,19 @@
-const { defaultFilters, database: { schemas }, map: { legacyPkmnFilter } } = require('../config')
+const {
+ defaultFilters,
+ map: { enableMapJsFilter },
+} = require('../config')
const buildPokemon = require('./buildPokemon')
const buildPokestops = require('./buildPokestops')
const buildGyms = require('./buildGyms')
const { GenericFilter, PokemonFilter } = require('../../models/index')
const base = new PokemonFilter()
-base.pvp()
const custom = new PokemonFilter(...Object.values(defaultFilters.pokemon.globalValues))
-custom.pvp(defaultFilters.pokemon.pvpValues)
module.exports = function buildDefault(perms) {
const stopReducer = perms.pokestops || perms.lures || perms.quests || perms.invasions
const gymReducer = perms.gyms || perms.raids
- const pokemonReducer = perms.iv || perms.stats || perms.pvp
- const hasAr = poi => Object.values(schemas).some(
- schema => schema.useFor.includes(poi) && schema.arScanColumn === true,
- )
+ const pokemonReducer = perms.iv || perms.pvp
const pokemon = buildPokemon(defaultFilters, base, custom)
return {
@@ -25,7 +23,7 @@ module.exports = function buildDefault(perms) {
raids: perms.raids ? defaultFilters.gyms.raids : undefined,
exEligible: perms.gyms ? defaultFilters.gyms.exEligible : undefined,
inBattle: perms.gyms ? defaultFilters.gyms.exEligible : undefined,
- arEligible: hasAr('gym') && perms.gyms ? false : undefined,
+ arEligible: perms.gyms ? false : undefined,
filter: {
...buildGyms(perms, defaultFilters.gyms),
...pokemon.raids,
@@ -44,7 +42,7 @@ module.exports = function buildDefault(perms) {
quests: perms.quests ? defaultFilters.pokestops.quests : undefined,
showQuestSet: defaultFilters.pokestops.questSet,
invasions: perms.invasions ? defaultFilters.pokestops.invasions : undefined,
- arEligible: hasAr('pokestop') && perms.pokestops ? false : undefined,
+ arEligible: perms.pokestops ? false : undefined,
filter: {
...buildPokestops(perms, defaultFilters.pokestops),
...pokemon.quests,
@@ -52,9 +50,8 @@ module.exports = function buildDefault(perms) {
} : undefined,
pokemon: perms.pokemon ? {
enabled: defaultFilters.pokemon.enabled,
- legacy: (pokemonReducer && legacyPkmnFilter) ? defaultFilters.pokemon.legacyFilter : undefined,
+ legacy: (pokemonReducer && enableMapJsFilter) ? defaultFilters.pokemon.legacyFilter : undefined,
iv: perms.iv ? true : undefined,
- stats: perms.stats ? true : undefined,
pvp: perms.pvp ? true : undefined,
standard: base,
ivOr: custom,
@@ -92,7 +89,7 @@ module.exports = function buildDefault(perms) {
unconfirmed: new GenericFilter(),
},
} : undefined,
- s2cells: perms.s2cells ? {
+ scanCells: perms.scanCells ? {
enabled: defaultFilters.scanCells.enabled,
filter: { global: new GenericFilter() },
} : undefined,
diff --git a/server/src/services/functions/areaPerms.js b/server/src/services/functions/areaPerms.js
index 4d4499d2f..58dc17e4d 100644
--- a/server/src/services/functions/areaPerms.js
+++ b/server/src/services/functions/areaPerms.js
@@ -1,11 +1,11 @@
const areas = require('../areas')
const config = require('../config')
-module.exports = function areaPerms(roles, provider) {
+module.exports = function areaPerms(roles) {
let perms = []
if (Object.keys(areas.names).length) {
roles.forEach(group => {
- config[provider].areaRestrictions.forEach(rule => {
+ config.authentication.areaRestrictions.forEach(rule => {
if (rule.roles.includes(group)) {
if (rule.areas.length) {
rule.areas.forEach(areaName => {
diff --git a/server/src/services/functions/dbSelection.js b/server/src/services/functions/dbSelection.js
index 75719393e..bd9106f6a 100644
--- a/server/src/services/functions/dbSelection.js
+++ b/server/src/services/functions/dbSelection.js
@@ -3,6 +3,5 @@ const { database: { schemas } } = require('../config')
module.exports = function dbSelection(category) {
if (category === 'quest' || category === 'invasion' || category === 'lure') category = 'pokestop'
if (category === 'raid') category = 'gym'
- const db = Object.values(schemas).find(({ useFor }) => useFor.includes(category))
- return db.type
+ return schemas.find(({ useFor }) => useFor.includes(category))
}
diff --git a/server/src/services/functions/permissions.js b/server/src/services/functions/permissions.js
index 457d58d63..d93cdfcdf 100644
--- a/server/src/services/functions/permissions.js
+++ b/server/src/services/functions/permissions.js
@@ -16,8 +16,6 @@ module.exports = function permissionManager(permToCheck, perms) {
case 'monsters':
case 'pokemon':
case 'pokemons': return perms.pokemon
- case 'stat':
- case 'stats': return perms.stats
case 'iv':
case 'ivs': return perms.iv
case 'pvp':
diff --git a/server/src/services/legacyFilter.js b/server/src/services/legacyFilter.js
index 6e99274fa..e78919f4e 100644
--- a/server/src/services/legacyFilter.js
+++ b/server/src/services/legacyFilter.js
@@ -6,10 +6,7 @@
const requireFromString = require('require-from-string')
const masterfile = require('../data/masterfile.json')
const {
- api: { pvpMinCp },
- database: {
- settings: { reactMapHandlesPvp },
- },
+ api: { pvp: { minCp: pvpMinCp, reactMapHandlesPvp } },
} = require('./config')
const jsifyIvFilter = (filter) => {
@@ -251,7 +248,7 @@ const getLegacy = (results, args, perms, ohbem) => {
result.seen_type = 'encounter'
}
}
- if (perms.iv || perms.stats) {
+ if (perms.iv) {
filtered.atk_iv = result.atk_iv
filtered.def_iv = result.def_iv
filtered.sta_iv = result.sta_iv
@@ -324,7 +321,7 @@ const getLegacy = (results, args, perms, ohbem) => {
filtered.cellId = result.cell_id
filtered.expire_timestamp_verified = result.expire_timestamp_verified
filtered.display_pokemon_id = result.display_pokemon_id
- if (perms.iv || perms.stats) {
+ if (perms.iv) {
filtered.move_1 = result.move_1
filtered.move_2 = result.move_2
filtered.weight = result.weight
diff --git a/server/src/services/logUserAuth.js b/server/src/services/logUserAuth.js
index 4cf593a3c..2244a6b8f 100644
--- a/server/src/services/logUserAuth.js
+++ b/server/src/services/logUserAuth.js
@@ -1,14 +1,12 @@
/* eslint-disable no-console */
const Fetch = require('./Fetch')
-const config = require('./config')
module.exports = async function getAuthInfo(req, user, strategy) {
const ip = req.headers['cf-connecting-ip']
|| ((req.headers['x-forwarded-for'] || '').split(', ')[0])
|| (req.connection.remoteAddress || req.connection.localAddress).match('[0-9]+.[0-9].+[0-9]+.[0-9]+$')[0]
- const url = `http://ip-api.com/json/${ip}?fields=66846719&lang=${config.map.locale || 'en'}`
- const geo = await Fetch.fetchJson(url)
+ const geo = await Fetch.fetchJson(`http://ip-api.com/json/${ip}?fields=66846719&lang=en`)
const embed = {
color: 0xFF0000,
title: 'Authentication',
diff --git a/server/src/services/sessionStore.js b/server/src/services/sessionStore.js
index 4331c44a5..cc01e7443 100644
--- a/server/src/services/sessionStore.js
+++ b/server/src/services/sessionStore.js
@@ -2,25 +2,27 @@
const session = require('express-session')
const MySQLStore = require('express-mysql-session')(session)
-const config = require('./config')
-
-const { database: { schemas } } = config
-
-const dbSelection = Object.keys(schemas).find(name => schemas[name].useFor.includes('session')) || 'scanner'
+const {
+ api: { maxSessions },
+ database: { settings: { sessionTableName } },
+} = require('./config')
+const Utility = require('./Utility')
const { Session } = require('../models/index')
+const dbSelection = Utility.dbSelection('session')
+
// MySQL session store
const sessionStore = new MySQLStore({
// Database server IP address/hostname
- host: schemas[dbSelection].host,
+ host: dbSelection.host,
// Database server listening port
- port: schemas[dbSelection].port,
+ port: dbSelection.port,
// Database username
- user: schemas[dbSelection].username,
+ user: dbSelection.username,
// Password for the above database user
- password: schemas[dbSelection].password,
+ password: dbSelection.password,
// Database name to save sessions table to
- database: schemas[dbSelection].database,
+ database: dbSelection.database,
// Whether or not to automatically check for and clear expired sessions:
clearExpired: true,
// How frequently expired sessions will be cleared; milliseconds:
@@ -29,7 +31,7 @@ const sessionStore = new MySQLStore({
createDatabaseTable: true,
// Set Sessions table name
schema: {
- tableName: config.database.settings.sessionTableName,
+ tableName: sessionTableName,
},
})
@@ -39,7 +41,7 @@ const isValidSession = async (userId) => {
.select('session_id')
.whereRaw(`json_extract(data, '$.passport.user.id') = ${userId}`)
.andWhere('expires', '>=', ts)
- return results.length < config.api.maxSessions
+ return results.length < maxSessions
}
const clearOtherSessions = async (userId, currentSessionId, botName) => {
diff --git a/server/src/services/ui/clientOptions.js b/server/src/services/ui/clientOptions.js
index cd5756d70..4cfe8a9ac 100644
--- a/server/src/services/ui/clientOptions.js
+++ b/server/src/services/ui/clientOptions.js
@@ -1,4 +1,8 @@
-const { clientSideOptions, map: { legacyPkmnFilter }, database: { settings: { pvpLevels } } } = require('../config')
+const {
+ clientSideOptions,
+ map: { enableMapJsFilter },
+ api: { pvp: { levels } },
+} = require('../config')
const dbSelection = require('../functions/dbSelection')
module.exports = function clientOptions(perms) {
@@ -42,20 +46,20 @@ module.exports = function clientOptions(perms) {
},
}
- pvpLevels.forEach(level => {
+ levels.forEach(level => {
clientMenus.pokemon[`pvp${level}`] = {
type: 'bool', perm: ['pvp'], value: true,
}
})
// special case options that require additional checks
- if (legacyPkmnFilter) {
- clientMenus.pokemon.legacyFilter = { type: 'bool', perm: ['iv', 'stats', 'pvp'] }
+ if (enableMapJsFilter) {
+ clientMenus.pokemon.legacyFilter = { type: 'bool', perm: ['iv', 'pvp'] }
}
if (clientSideOptions.pokemon.glow.length > 0) {
clientMenus.pokemon.glow = { type: 'bool', sub: {}, perm: ['pokemon'] }
}
- if (dbSelection('pokestop') === 'mad') {
+ if (dbSelection('pokestop').type === 'mad') {
clientMenus.pokestops.madQuestText = { type: 'bool', perm: ['quests'] }
}
diff --git a/server/src/services/ui/primary.js b/server/src/services/ui/primary.js
index 8eb92da32..553f8a9d7 100644
--- a/server/src/services/ui/primary.js
+++ b/server/src/services/ui/primary.js
@@ -1,5 +1,5 @@
/* eslint-disable no-restricted-syntax */
-const { database: { settings: { leagues } } } = require('../config')
+const { api: { pvp: { leagues } } } = require('../config')
module.exports = function generateUi(filters, perms) {
const ui = {}
@@ -21,16 +21,16 @@ module.exports = function generateUi(filters, perms) {
],
secondary: [
{
- name: 'level', label: '', min: 1, max: 35, perm: 'stats',
+ name: 'level', label: '', min: 1, max: 35, perm: 'iv',
},
{
- name: 'atk_iv', label: '', min: 0, max: 15, perm: 'stats',
+ name: 'atk_iv', label: '', min: 0, max: 15, perm: 'iv',
},
{
- name: 'def_iv', label: '', min: 0, max: 15, perm: 'stats',
+ name: 'def_iv', label: '', min: 0, max: 15, perm: 'iv',
},
{
- name: 'sta_iv', label: '', min: 0, max: 15, perm: 'stats',
+ name: 'sta_iv', label: '', min: 0, max: 15, perm: 'iv',
},
],
}
@@ -42,7 +42,7 @@ module.exports = function generateUi(filters, perms) {
if (!ui.wayfarer) ui.wayfarer = {}
ui.wayfarer[key] = true; break
case 'spawnpoints':
- case 's2cells':
+ case 'scanCells':
case 'devices':
if (!ui.admin) ui.admin = {}
ui.admin[key] = true; break
@@ -62,7 +62,7 @@ module.exports = function generateUi(filters, perms) {
case 'submissionCells':
case 'portals': ui.wayfarer[key] = true; break
case 'spawnpoints':
- case 's2cells':
+ case 'scanCells':
case 'devices': ui.admin[key] = true; break
case 'scanAreas':
case 'weather': ui[key].enabled = true; break
diff --git a/server/src/services/ui/webhook.js b/server/src/services/ui/webhook.js
index 596618771..dd1855ca7 100644
--- a/server/src/services/ui/webhook.js
+++ b/server/src/services/ui/webhook.js
@@ -47,15 +47,15 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) {
primary: {
sliders: [
{ name: 'iv', label: '', min: -1, max: 100, perm: 'iv', low: 'min_iv', high: 'max_iv' },
- { name: 'level', label: '', min: 0, max: 40, perm: 'stats', low: 'min_level', high: 'max_level' },
+ { name: 'level', label: '', min: 0, max: 40, perm: 'iv', low: 'min_level', high: 'max_level' },
],
},
advanced: {
sliders: [
- { name: 'cp', label: '', min: 0, max: 9000, perm: 'stats', low: 'min_cp', high: 'max_cp' },
- { name: 'atk_iv', label: '', min: 0, max: 15, perm: 'stats', low: 'atk', high: 'max_atk' },
- { name: 'def_iv', label: '', min: 0, max: 15, perm: 'stats', low: 'def', high: 'max_def' },
- { name: 'sta_iv', label: '', min: 0, max: 15, perm: 'stats', low: 'sta', high: 'max_sta' },
+ { name: 'cp', label: '', min: 0, max: 9000, perm: 'iv', low: 'min_cp', high: 'max_cp' },
+ { name: 'atk_iv', label: '', min: 0, max: 15, perm: 'iv', low: 'atk', high: 'max_atk' },
+ { name: 'def_iv', label: '', min: 0, max: 15, perm: 'iv', low: 'def', high: 'max_def' },
+ { name: 'sta_iv', label: '', min: 0, max: 15, perm: 'iv', low: 'sta', high: 'max_sta' },
],
texts: [{ name: 'min_time', type: 'number', max: 60, adornment: 's', xs: 4, sm: 4, width: 100 }],
booleans: [
diff --git a/server/src/strategies/discord.js b/server/src/strategies/discord.js
index 2983b444a..3d4fa2bab 100644
--- a/server/src/strategies/discord.js
+++ b/server/src/strategies/discord.js
@@ -6,7 +6,10 @@ const path = require('path')
// if writing a custom strategy, rename 'discord' below to your strategy name
// this will automatically grab all of its unique values in the config
-const { map: { forceTutorial }, discord: strategyConfig } = require('../services/config')
+const {
+ map: { forceTutorial },
+ authentication: { discord: strategyConfig, perms },
+} = require('../services/config')
const { User } = require('../models/index')
const DiscordMapClient = require('../services/DiscordClient')
const logUserAuth = require('../services/logUserAuth')
@@ -26,7 +29,7 @@ client.on('ready', () => {
client.login(strategyConfig.botToken)
-const MapClient = new DiscordMapClient(client, strategyConfig)
+const MapClient = new DiscordMapClient(client, { ...strategyConfig, perms })
const authHandler = async (req, accessToken, refreshToken, profile, done) => {
if (!req.query.code) {
diff --git a/server/src/strategies/local.js b/server/src/strategies/local.js
index c286095d1..99e00337e 100644
--- a/server/src/strategies/local.js
+++ b/server/src/strategies/local.js
@@ -6,18 +6,26 @@ const path = require('path')
// if writing a custom strategy, rename 'local' below to your strategy name
// this will automatically grab all of its unique values in the config
-const { map: { forceTutorial }, local: strategyConfig, discord, alwaysEnabledPerms } = require('../services/config')
+const {
+ map: { forceTutorial },
+ authentication: { local: strategyConfig, alwaysEnabledPerms, perms },
+} = require('../services/config')
const { User } = require('../models/index')
const Utility = require('../services/Utility')
+if (strategyConfig.doNothing) {
+ // This is for nothing other than demonstrating how to implement a custom local strategy with the above instructions
+}
+
const authHandler = async (req, username, password, done) => {
+ const localPerms = Object.keys(perms).filter(key => perms[key].roles.includes('local'))
const user = {
perms: {
...Object.fromEntries(
- Object.keys(discord.perms)
- .map(x => [x, strategyConfig.perms.includes(x) || alwaysEnabledPerms.includes(x)]),
+ Object.keys(perms)
+ .map(perm => [perm, localPerms.includes(perm) || alwaysEnabledPerms.includes(perm)]),
),
- areaRestrictions: Utility.areaPerms(strategyConfig.perms, 'local'),
+ areaRestrictions: Utility.areaPerms(localPerms, 'local'),
webhooks: [],
},
}
@@ -42,9 +50,9 @@ const authHandler = async (req, username, password, done) => {
}
}
if (bcrypt.compareSync(password, userExists.password)) {
- ['discordPerms', 'telegramPerms'].forEach((perms) => {
- if (userExists[perms]) {
- user.perms = Utility.mergePerms(user.perms, JSON.parse(userExists[perms]))
+ ['discordPerms', 'telegramPerms'].forEach((permSet) => {
+ if (userExists[permSet]) {
+ user.perms = Utility.mergePerms(user.perms, userExists[permSet])
}
})
if (userExists.strategy !== 'local') {
diff --git a/server/src/strategies/telegram.js b/server/src/strategies/telegram.js
index a7919fc75..ccb27e6c9 100644
--- a/server/src/strategies/telegram.js
+++ b/server/src/strategies/telegram.js
@@ -5,7 +5,10 @@ const path = require('path')
// if writing a custom strategy, rename 'telegram' below to your strategy name
// this will automatically grab all of its unique values in the config
-const { map: { forceTutorial }, telegram: strategyConfig, alwaysEnabledPerms } = require('../services/config')
+const {
+ map: { forceTutorial },
+ authentication: { telegram: strategyConfig, perms, alwaysEnabledPerms },
+} = require('../services/config')
const { User } = require('../models/index')
const Fetch = require('../services/Fetch')
const Utility = require('../services/Utility')
@@ -14,7 +17,7 @@ const authHandler = async (req, profile, done) => {
const user = {
...profile,
perms: {
- ...Object.fromEntries(Object.keys(strategyConfig.perms).map(x => [x, false])),
+ ...Object.fromEntries(Object.keys(perms).map(x => [x, false])),
areaRestrictions: [],
webhooks: [],
},
@@ -36,7 +39,7 @@ const authHandler = async (req, profile, done) => {
}
}))
- Object.entries(strategyConfig.perms).forEach(([perm, info]) => {
+ Object.entries(perms).forEach(([perm, info]) => {
if (info.enabled && (alwaysEnabledPerms.includes(perm)
|| info.roles.some(role => groupInfo.includes(role)))) {
user.perms[perm] = true
diff --git a/src/components/Clustering.jsx b/src/components/Clustering.jsx
index 068d90dcc..25df20bd6 100644
--- a/src/components/Clustering.jsx
+++ b/src/components/Clustering.jsx
@@ -12,10 +12,10 @@ const getId = (component, item) => {
case 'nests': return item.nest_id
}
}
-const ignoredClustering = ['devices', 'submissionCells', 's2cells', 'weather']
+const ignoredClustering = ['devices', 'submissionCells', 'scanCells', 'weather']
export default function Clustering({
- category, renderedData, userSettings, clusterZoomLvl, staticUserSettings, params,
+ category, renderedData, userSettings, clusteringRules, staticUserSettings, params,
filters, map, Icons, perms, tileStyle, config, userIcons, setParams, isNight,
}) {
const Component = index[category]
@@ -58,14 +58,14 @@ export default function Clustering({
return null
})
- const limitHit = finalData.length > config.clusterZoomLevels.forcedClusterLimit
+ const limitHit = finalData.length > clusteringRules.forcedLimit
&& !ignoredClustering.includes(category)
- return limitHit || (clusterZoomLvl && userSettings.clustering) ? (
+ return limitHit || (clusteringRules.zoomLevel && userSettings.clustering) ? (
<>
{finalData}
@@ -77,7 +77,7 @@ export default function Clustering({
messages={[
{
key: 'limitHit',
- variables: [category, config.clusterZoomLevels.forcedClusterLimit],
+ variables: [category, clusteringRules.forcedLimit],
},
{
key: 'zoomIn',
diff --git a/src/components/ConfigSettings.jsx b/src/components/ConfigSettings.jsx
index 1a1e3daf7..f1bef75fd 100644
--- a/src/components/ConfigSettings.jsx
+++ b/src/components/ConfigSettings.jsx
@@ -95,6 +95,16 @@ export default function ConfigSettings({
const cached = localState.state.settings.localeSelection
const i18cached = localStorage.getItem('i18nextLng')
localState.state.settings.localeSelection = cached !== i18cached ? i18cached : cached
+
+ const validNav = Object.keys(serverSettings.config.navigation)
+ localState.state.settings.navigation = validNav.includes(localState.state.settings.navigation)
+ ? localState.state.settings.navigation
+ : serverSettings.config.navigation[validNav[0]]?.name
+
+ const validTs = Object.keys(serverSettings.config.tileServers)
+ localState.state.settings.tileServers = validTs.includes(localState.state.settings.tileServers)
+ ? localState.state.settings.tileServers
+ : serverSettings.config.tileServers[validTs[0]]?.name
} else {
serverSettings.settings.localeSelection = localStorage.getItem('i18nextLng') || serverSettings.settings.localeSelection
}
diff --git a/src/components/Map.jsx b/src/components/Map.jsx
index ffa58fd1b..f246bb37f 100644
--- a/src/components/Map.jsx
+++ b/src/components/Map.jsx
@@ -10,12 +10,12 @@ import Webhook from './layout/dialogs/webhooks/Webhook'
const userSettingsCategory = category => {
switch (category) {
- default: return category
case 'devices':
case 'spawnpoints':
- case 's2cells': return 'admin'
+ case 'scanCells': return 'admin'
case 'submissionCells':
case 'portals': return 'wayfarer'
+ default: return category
}
}
@@ -79,9 +79,9 @@ export default function Map({ serverSettings: { config: { map: config, tileServe
return (
<>
OpenStreetMap, under ODbL.'}
+ url={tileServer?.url || 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png'}
minZoom={config.minZoom}
maxZoom={config.maxZoom}
/>
@@ -155,8 +155,8 @@ export default function Map({ serverSettings: { config: { map: config, tileServe
userIcons={icons}
userSettings={userSettings[userSettingsCategory(category)] || {}}
filters={filters[category]}
- tileStyle={tileServer.style}
- clusterZoomLvl={config.clusterZoomLevels[category]}
+ tileStyle={tileServer?.style || 'light'}
+ clusteringRules={config.clustering[category] || { zoomLimit: config.minZoom, forcedLimit: 10000 }}
staticUserSettings={staticUserSettings[category]}
params={manualParams}
setParams={setManualParams}
diff --git a/src/components/QueryData.jsx b/src/components/QueryData.jsx
index a3d9d2095..f4644c725 100644
--- a/src/components/QueryData.jsx
+++ b/src/components/QueryData.jsx
@@ -14,7 +14,7 @@ const getPolling = category => {
switch (category) {
case 'devices':
case 'gyms':
- case 's2cells':
+ case 'scanCells':
return 10 * 1000
case 'pokemon':
return 20 * 1000
@@ -25,7 +25,7 @@ const getPolling = category => {
}
export default function QueryData({
- bounds, onMove, map, tileStyle, clusterZoomLvl, config, params,
+ bounds, onMove, map, tileStyle, clusteringRules, config, params,
category, available, filters, staticFilters, staticUserSettings, sizeKey,
userSettings, perms, Icons, userIcons, setParams, isNight, setExcludeList,
}) {
@@ -87,7 +87,7 @@ export default function QueryData({
}, [filters, userSettings])
const { data, previousData, refetch, error } = useQuery(Query[category](
- filters, perms, map.getZoom(), clusterZoomLvl,
+ filters, perms, map.getZoom(), clusteringRules.zoomLevel,
), {
context: { timeout: getPolling(category) },
variables: {
@@ -119,7 +119,7 @@ export default function QueryData({
setWebhookMode(false), icon: 'Close', color: 'primary' },
]
- if (map.enableFeedback) {
+ if (map.feedbackLink) {
footerButtons.unshift(
{ name: 'feedback', action: () => setFeedback(true), icon: 'BugReport', disabled: !webhookData[selectedWebhook].human, color: '#00e676' },
)
diff --git a/src/components/layout/drawer/Areas.jsx b/src/components/layout/drawer/Areas.jsx
index f4be7947f..a861d31e6 100644
--- a/src/components/layout/drawer/Areas.jsx
+++ b/src/components/layout/drawer/Areas.jsx
@@ -29,8 +29,8 @@ export default function AreaDropDown({ scanAreasZoom, manualAreas }) {