diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1a6a9d146..c6dca5b7c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -6,10 +6,31 @@ env: IMAGE_NAME: ${{ github.repository }} jobs: + Sync: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + fetch-depth: 2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + cache: "yarn" + - name: Generate latest env vars + run: | + yarn gen-env-config + - name: Commit and push changes + uses: devops-infra/action-commit-push@v0.9.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + commit_message: Synced docker env vars with latest config Docker: + needs: Sync runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set .gitsha if: github.event_name == 'push' diff --git a/README.md b/README.md index 9bfd83979..319aa31f1 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ Pokemon GO Map frontend built with React. - Last Scanned Cells - Spawnpoints - Discord, Telegram, Local, and Custom Auth & Permission Based Viewing +- Gym Badge tracking +- Webhook alert management for [Poracle](https://github.com/KartulUdus/PoracleJS) - Extremely configurable and supports custom, git friendly, code injection ## Live Demo diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 05ffe3a91..d256f635b 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -15,7 +15,7 @@ import aliasPlugin from 'esbuild-plugin-path-alias' import { eslintPlugin } from 'esbuild-plugin-eslinter' const __dirname = path.dirname(fileURLToPath(import.meta.url)) -const env = fs.existsSync(`${__dirname}/.env`) ? dotenv.config() : { parsed: {} } +const env = fs.existsSync(`${__dirname}/.env`) ? dotenv.config() : { parsed: process.env } const { version } = JSON.parse(fs.readFileSync(path.resolve(__dirname, 'package.json'))) const isDevelopment = Boolean(process.argv.includes('--dev')) const isRelease = Boolean(process.argv.includes('--release')) diff --git a/package.json b/package.json index 116bc2685..8a9a275ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "reactmap", - "version": "1.2.5", + "version": "1.2.6", "description": "React based frontend map.", "main": "ReactMap.mjs", "author": "TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com>", diff --git a/public/base-locales/de.json b/public/base-locales/de.json index 32c2521d7..fbb30df1b 100644 --- a/public/base-locales/de.json +++ b/public/base-locales/de.json @@ -167,7 +167,8 @@ "gyms_options": "Arena Optionen", "nests_options": "Nest Optionen", "wayfarer_options": "Wayfarer Optionen", - "admin_options": "Admin Option", + "admin_options": "Admin Optionen", + "weather_options": "Wetter Optionen", "clustering": "Clustering", "glow": "Leuchten", "legacy_filter": "Legacy Filter", @@ -538,5 +539,13 @@ "points": "Punkte", "day": "Tag", "days": "Tage", - "react_error": "Etwas ist schiefgelaufen" + "react_error": "Etwas ist schiefgelaufen", + "clickable_icon": "Icon ist anklickbar", + "two_stops_till_next": "2 Stops bis zur nächsten", + "one_stop_till_next": "1 Stop bis zur nächsten", + "no_more_gyms": "keine weitere Arena", + "light_map_border": "heller Kartenrand", + "dark_map_border": "dunkler Kartenrand", + "cell_blocked": "Zelle ist blockiert", + "poi_color": "POI Farbe" } diff --git a/public/base-locales/en.json b/public/base-locales/en.json index b07c3119c..80ffee9ea 100644 --- a/public/base-locales/en.json +++ b/public/base-locales/en.json @@ -535,5 +535,12 @@ "day": "Day", "days": "Days", "react_error": "Something Went Wrong", - "clickable_icon": "Icon is Clickable" + "clickable_icon": "Icon is Clickable", + "two_stops_till_next": "2 stops until next", + "one_stop_till_next": "1 stop until next", + "no_more_gyms": "No more gyms", + "light_map_border": "Light Map Border", + "dark_map_border": "Dark Map Border", + "cell_blocked": "Cell Blocked", + "poi_color": "POI Color" } diff --git a/public/base-locales/es.json b/public/base-locales/es.json index 1c7b4d674..5f1295a60 100644 --- a/public/base-locales/es.json +++ b/public/base-locales/es.json @@ -530,5 +530,14 @@ "points": "Puntos", "day": "Día", "days": "Dias", - "react_error": "Algo salió mal" + "react_error": "Algo salió mal", + "clickable_icon": "Se puede hacer clic en el icono", + "weather_options": "Opciones meteorológicas", + "two_stops_till_next": "2 paradas hasta la próxima", + "one_stop_till_next": "1 parada hasta la próxima", + "no_more_gyms": "No más gimnasios", + "light_map_border": "Borde de mapa claro", + "dark_map_border": "Borde oscuro del mapa", + "cell_blocked": "Celda bloqueada", + "poi_color": "Color de punto de interés" } diff --git a/public/base-locales/fr.json b/public/base-locales/fr.json index 4bb7be8f4..33980ba46 100644 --- a/public/base-locales/fr.json +++ b/public/base-locales/fr.json @@ -537,5 +537,14 @@ "points": "Points", "day": "Jour", "days": "Jours", - "react_error": "Un problème est survenu" + "react_error": "Un problème est survenu", + "clickable_icon": "L'icône est cliquable", + "weather_options": "Options météo", + "two_stops_till_next": "2 arrêts jusqu'à la prochaine", + "one_stop_till_next": "1 arrêt jusqu'au prochain", + "no_more_gyms": "Plus de gymnases", + "light_map_border": "Bordure de carte lumineuse", + "dark_map_border": "Bordure de carte sombre", + "cell_blocked": "Cellule bloquée", + "poi_color": "Couleur du point d'intérêt" } diff --git a/public/base-locales/it.json b/public/base-locales/it.json index a7c47b805..3a549824a 100644 --- a/public/base-locales/it.json +++ b/public/base-locales/it.json @@ -501,5 +501,14 @@ "days": "Giorni", "scan_cells_subtitle": "Mostra l'ultima volta che una cella S2 è stata scansionata da un dispositivo", "locale_selection_ja": "日本語", - "react_error": "Qualcosa è andato storto" + "react_error": "Qualcosa è andato storto", + "clickable_icon": "L'icona è cliccabile", + "weather_options": "Opzioni meteo", + "two_stops_till_next": "2 fermate fino al prossimo", + "one_stop_till_next": "1 fermata fino al prossimo", + "no_more_gyms": "Niente più palestre", + "light_map_border": "Bordo mappa chiaro", + "dark_map_border": "Bordo mappa scuro", + "cell_blocked": "Cella bloccata", + "poi_color": "Colore PDI" } diff --git a/public/base-locales/ja.json b/public/base-locales/ja.json index 6f7dfc59e..e7000de54 100644 --- a/public/base-locales/ja.json +++ b/public/base-locales/ja.json @@ -501,5 +501,14 @@ "day": "日", "days": "日々", "scan_cells_subtitle": "S2セルがデバイスによって最後にスキャンされた時刻を示します", - "react_error": "何かがおかしい" + "react_error": "何かがおかしい", + "clickable_icon": "アイコンはクリック可能", + "weather_options": "天気オプション", + "two_stops_till_next": "次まで2ストップ", + "one_stop_till_next": "次まで1ストップ", + "no_more_gyms": "これ以上のジムはありません", + "light_map_border": "ライトマップボーダー", + "dark_map_border": "ダークマップボーダー", + "cell_blocked": "セルがブロックされました", + "poi_color": "POIカラー" } diff --git a/public/base-locales/ko.json b/public/base-locales/ko.json index 7beca6610..4f952aff7 100644 --- a/public/base-locales/ko.json +++ b/public/base-locales/ko.json @@ -501,5 +501,14 @@ "days": "날", "scan_cells_subtitle": "장치가 S2 셀을 마지막으로 스캔한 시간을 표시합니다.", "locale_selection_nl": "네덜란드", - "react_error": "문제가 발생했습니다." + "react_error": "문제가 발생했습니다.", + "clickable_icon": "아이콘을 클릭할 수 있음", + "weather_options": "날씨 옵션", + "two_stops_till_next": "다음까지 2정거장", + "one_stop_till_next": "다음까지 1정거장", + "no_more_gyms": "더 이상 체육관은 없습니다", + "light_map_border": "라이트 맵 테두리", + "dark_map_border": "어두운 지도 테두리", + "cell_blocked": "차단된 셀", + "poi_color": "POI 색상" } diff --git a/public/base-locales/nl.json b/public/base-locales/nl.json index fb867a36a..c13fd8a41 100644 --- a/public/base-locales/nl.json +++ b/public/base-locales/nl.json @@ -533,5 +533,14 @@ "points": "Punten", "day": "Dag", "days": "Dagen", - "react_error": "Er ging iets mis" + "react_error": "Er ging iets mis", + "clickable_icon": "Icoon is klikbaar", + "weather_options": "Weer opties", + "two_stops_till_next": "2 haltes tot de volgende", + "one_stop_till_next": "1 halte tot de volgende", + "no_more_gyms": "Geen sportscholen meer", + "light_map_border": "Lichte kaartrand", + "dark_map_border": "Donkere kaartrand", + "cell_blocked": "Cel geblokkeerd", + "poi_color": "POI-kleur" } diff --git a/public/base-locales/pt-br.json b/public/base-locales/pt-br.json index 0b79c6ab7..4dd220e57 100644 --- a/public/base-locales/pt-br.json +++ b/public/base-locales/pt-br.json @@ -501,5 +501,14 @@ "days": "Dias", "scan_cells_subtitle": "Mostra a última vez que uma célula S2 foi verificada por um dispositivo", "locale_selection_nl": "Países Baixos", - "react_error": "Algo deu errado" + "react_error": "Algo deu errado", + "clickable_icon": "O ícone é clicável", + "weather_options": "Opções de clima", + "two_stops_till_next": "2 paradas até a próxima", + "one_stop_till_next": "1 parada até a próxima", + "no_more_gyms": "Não há mais ginásios", + "light_map_border": "Borda do mapa de luz", + "dark_map_border": "Borda do mapa escuro", + "cell_blocked": "Célula bloqueada", + "poi_color": "Cor do POI" } diff --git a/public/base-locales/ru.json b/public/base-locales/ru.json index ae931ce53..07b01f737 100644 --- a/public/base-locales/ru.json +++ b/public/base-locales/ru.json @@ -501,5 +501,14 @@ "days": "Дни", "scan_cells_subtitle": "Показывает, когда устройство последний раз сканировало ячейку S2.", "locale_selection_nl": "Нидерланды", - "react_error": "Что-то пошло не так" + "react_error": "Что-то пошло не так", + "clickable_icon": "Иконка кликабельна", + "weather_options": "Параметры погоды", + "two_stops_till_next": "2 остановки до следующей", + "one_stop_till_next": "1 остановка до следующей", + "no_more_gyms": "Нет больше тренажерных залов", + "light_map_border": "Граница световой карты", + "dark_map_border": "Темная граница карты", + "cell_blocked": "Сотовый заблокирован", + "poi_color": "Цвет POI" } diff --git a/public/base-locales/sv.json b/public/base-locales/sv.json index 9d039d6b3..e1804caff 100644 --- a/public/base-locales/sv.json +++ b/public/base-locales/sv.json @@ -501,5 +501,14 @@ "days": "dagar", "scan_cells_subtitle": "Visar senaste gången en S2-cell skannades av en enhet", "locale_selection_nl": "nederländska", - "react_error": "Något gick fel" + "react_error": "Något gick fel", + "clickable_icon": "Ikonen är klickbar", + "weather_options": "Väderalternativ", + "two_stops_till_next": "2 stopp till nästa", + "one_stop_till_next": "1 stopp till nästa", + "no_more_gyms": "Inga fler gym", + "light_map_border": "Ljus kartgräns", + "dark_map_border": "Mörk kartgräns", + "cell_blocked": "Cell blockerad", + "poi_color": "POI-färg" } diff --git a/public/base-locales/th.json b/public/base-locales/th.json index 3321e74af..54377f2f4 100644 --- a/public/base-locales/th.json +++ b/public/base-locales/th.json @@ -501,5 +501,14 @@ "days": "วัน", "scan_cells_subtitle": "แสดงครั้งสุดท้ายที่อุปกรณ์ S2 สแกนเซลล์", "locale_selection_nl": "เนเธอร์แลนด์", - "react_error": "อะไรบางอย่างผิดปกติ" + "react_error": "อะไรบางอย่างผิดปกติ", + "clickable_icon": "ไอคอนคลิกได้", + "weather_options": "ตัวเลือกสภาพอากาศ", + "two_stops_till_next": "2 หยุดจนกว่าจะถึงถัดไป", + "one_stop_till_next": "1 หยุดจนกว่าจะถึงต่อไป", + "no_more_gyms": "ไม่มียิมอีกต่อไป", + "light_map_border": "เส้นขอบแผนที่แสง", + "dark_map_border": "เส้นขอบแผนที่มืด", + "cell_blocked": "เซลล์ถูกบล็อก", + "poi_color": "POI สี" } diff --git a/public/base-locales/tr.json b/public/base-locales/tr.json index e50a04b5a..d2feed361 100644 --- a/public/base-locales/tr.json +++ b/public/base-locales/tr.json @@ -1,3 +1,12 @@ { - "react_error": "Bir şeyler yanlış gitti" + "react_error": "Bir şeyler yanlış gitti", + "clickable_icon": "Simge Tıklanabilir", + "weather_options": "Hava Durumu Seçenekleri", + "two_stops_till_next": "bir sonrakine kadar 2 durak", + "one_stop_till_next": "bir sonrakine kadar 1 durak", + "no_more_gyms": "Artık spor salonu yok", + "light_map_border": "Hafif Harita Sınırı", + "dark_map_border": "Karanlık Harita Kenarlığı", + "cell_blocked": "Hücre Engellendi", + "poi_color": "POI Rengi" } diff --git a/public/base-locales/zh-tw.json b/public/base-locales/zh-tw.json index 7276e7996..b58851fe6 100644 --- a/public/base-locales/zh-tw.json +++ b/public/base-locales/zh-tw.json @@ -501,5 +501,14 @@ "days": "天", "scan_cells_subtitle": "顯示設備上次掃描 S2 單元的時間", "locale_selection_nl": "荷蘭", - "react_error": "出問題了" + "react_error": "出問題了", + "clickable_icon": "圖標可點擊", + "weather_options": "天氣選項", + "two_stops_till_next": "2 站直到下一站", + "one_stop_till_next": "1 站到下一個", + "no_more_gyms": "沒有健身房了", + "light_map_border": "光照貼圖邊框", + "dark_map_border": "深色地圖邊框", + "cell_blocked": "單元格阻塞", + "poi_color": "興趣點顏色" } diff --git a/server/src/configs/custom-environment-variables.json b/server/src/configs/custom-environment-variables.json index 763dbb187..17a45b7a6 100644 --- a/server/src/configs/custom-environment-variables.json +++ b/server/src/configs/custom-environment-variables.json @@ -318,7 +318,8 @@ "clientTimeoutMinutes": { "__name": "MAP_MISC_CLIENT_TIMEOUT_MINUTES", "__format": "number" - } + }, + "distanceUnit": "MAP_MISC_DISTANCE_UNIT" }, "theme": { "style": "MAP_THEME_STYLE", @@ -581,13 +582,22 @@ "__format": "boolean" }, "oldPortals": "CLIENT_SIDE_OPTIONS_WAYFARER_OLD_PORTALS", - "newPortals": "CLIENT_SIDE_OPTIONS_WAYFARER_NEW_PORTALS" + "newPortals": "CLIENT_SIDE_OPTIONS_WAYFARER_NEW_PORTALS", + "twoStopsTillNext": "CLIENT_SIDE_OPTIONS_WAYFARER_TWO_STOPS_TILL_NEXT", + "oneStopTillNext": "CLIENT_SIDE_OPTIONS_WAYFARER_ONE_STOP_TILL_NEXT", + "noMoreGyms": "CLIENT_SIDE_OPTIONS_WAYFARER_NO_MORE_GYMS", + "lightMapBorder": "CLIENT_SIDE_OPTIONS_WAYFARER_LIGHT_MAP_BORDER", + "darkMapBorder": "CLIENT_SIDE_OPTIONS_WAYFARER_DARK_MAP_BORDER", + "cellBlocked": "CLIENT_SIDE_OPTIONS_WAYFARER_CELL_BLOCKED", + "poiColor": "CLIENT_SIDE_OPTIONS_WAYFARER_POI_COLOR" }, "weather": { "clickableIcon": { "__name": "CLIENT_SIDE_OPTIONS_WEATHER_CLICKABLE_ICON", "__format": "boolean" - } + }, + "darkMapBorder": "CLIENT_SIDE_OPTIONS_WEATHER_DARK_MAP_BORDER", + "lightMapBorder": "CLIENT_SIDE_OPTIONS_WEATHER_LIGHT_MAP_BORDER" } }, "defaultFilters": { diff --git a/server/src/configs/default.json b/server/src/configs/default.json index f7e4e6005..30eb5ad33 100644 --- a/server/src/configs/default.json +++ b/server/src/configs/default.json @@ -133,7 +133,8 @@ "noScanAreaOverlay": false, "permImageDir": "images/perms", "permArrayImages": false, - "clientTimeoutMinutes": 30 + "clientTimeoutMinutes": 30, + "distanceUnit" : "km" }, "theme": { "style": "dark", @@ -260,10 +261,19 @@ "wayfarer": { "clustering": true, "oldPortals": "#0000ff", - "newPortals": "#16b819" + "newPortals": "#16b819", + "twoStopsTillNext": "#ffa500", + "oneStopTillNext": "#ff0000", + "noMoreGyms": "#000000", + "lightMapBorder": "#000000", + "darkMapBorder": "#ff0000", + "cellBlocked": "#000000", + "poiColor": "#03ffff" }, "weather": { - "clickableIcon": false + "clickableIcon": false, + "darkMapBorder": "#ff0000", + "lightMapBorder": "#246377" } }, "defaultFilters": { diff --git a/server/src/configs/local.example.json b/server/src/configs/local.example.json index 4cc1cd837..f7cc0591f 100644 --- a/server/src/configs/local.example.json +++ b/server/src/configs/local.example.json @@ -67,6 +67,7 @@ "database": { "schemas": [ { + "note": "Scanner Database", "host": "127.0.0.1", "port": 3306, "username": "scanner_user", @@ -83,14 +84,25 @@ ] }, { + "note": "React Map Database, where the migrations are ran through this app", + "host": "127.0.0.1", + "port": 3306, + "username": "reactmap_user", + "password": "reactmap_paw", + "database": "reactmap_db", + "useFor": [ + "session", + "user" + ] + }, + { + "note": "Manual Database generally used for storing nests or portal tables, more info on the Wiki", "host": "127.0.0.1", "port": 3306, "username": "manual_user", "password": "manual_pw", "database": "manual_db", "useFor": [ - "session", - "user", "nest", "portal" ] diff --git a/server/src/models/Pokestop.js b/server/src/models/Pokestop.js index df7ae364c..c58f181b7 100644 --- a/server/src/models/Pokestop.js +++ b/server/src/models/Pokestop.js @@ -150,126 +150,131 @@ module.exports = class Pokestop extends Model { } if (onlyQuests && questPerms) { stops.orWhere(quest => { - quest.where('quest_timestamp', '>=', midnight) - .andWhere(questTypes => { - questTypes.orWhereIn('quest_item_id', items) - .orWhereIn('quest_pokemon_id', pokemon) + quest.where(timestamps => { + timestamps.where('quest_timestamp', '>=', midnight) + if (hasAltQuests) { + timestamps.orWhere('alternative_quest_timestamp', '>=', midnight) + } + }) + quest.andWhere(questTypes => { + questTypes.orWhereIn('quest_item_id', items) + .orWhereIn('quest_pokemon_id', pokemon) + if (hasAltQuests) { + questTypes.orWhereIn('alternative_quest_item_id', items) + .orWhereIn('alternative_quest_pokemon_id', pokemon) + } + if (hasRewardAmount) { + questTypes.orWhereIn(isMad ? 'quest_stardust' : 'quest_reward_amount', stardust) if (hasAltQuests) { - questTypes.orWhereIn('alternative_quest_item_id', items) - .orWhereIn('alternative_quest_pokemon_id', pokemon) + questTypes.orWhereIn('alternative_quest_reward_amount', stardust) } + } else { + stardust.forEach(amount => { + questTypes.orWhere(dust => { + dust.where('quest_reward_type', 3) + .andWhere(raw(`json_extract(quest_rewards, "$[0].info.amount") = ${amount}`)) + }) + if (hasAltQuests) { + questTypes.orWhere(altDust => { + altDust.where('alternative_quest_reward_type', 3) + .andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.amount") = ${amount}`)) + }) + } + }) + } + energy.forEach(megaEnergy => { + const [pokeId, amount] = megaEnergy.split('-') if (hasRewardAmount) { - questTypes.orWhereIn(isMad ? 'quest_stardust' : 'quest_reward_amount', stardust) + questTypes.orWhere(mega => { + mega.where('quest_reward_type', 12) + .andWhere(isMad ? 'quest_item_amount' : 'quest_reward_amount', amount) + .andWhere('quest_pokemon_id', pokeId) + }) if (hasAltQuests) { - questTypes.orWhereIn('alternative_quest_reward_amount', stardust) + questTypes.orWhere(altMega => { + altMega.where('alternative_quest_reward_type', 12) + .andWhere('alternative_quest_reward_amount', amount) + .andWhere('alternative_quest_pokemon_id', pokeId) + }) } } else { - stardust.forEach(amount => { - questTypes.orWhere(dust => { - dust.where('quest_reward_type', 3) - .andWhere(raw(`json_extract(quest_rewards, "$[0].info.amount") = ${amount}`)) - }) - if (hasAltQuests) { - questTypes.orWhere(altDust => { - altDust.where('alternative_quest_reward_type', 3) - .andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.amount") = ${amount}`)) - }) - } - }) - } - energy.forEach(megaEnergy => { - const [pokeId, amount] = megaEnergy.split('-') - if (hasRewardAmount) { - questTypes.orWhere(mega => { - mega.where('quest_reward_type', 12) - .andWhere(isMad ? 'quest_item_amount' : 'quest_reward_amount', amount) + questTypes.orWhere(mega => { + mega.where('quest_reward_type', 12) + if (hasRewardAmount) { + mega.andWhere('quest_reward_amount', amount) .andWhere('quest_pokemon_id', pokeId) - }) - if (hasAltQuests) { - questTypes.orWhere(altMega => { - altMega.where('alternative_quest_reward_type', 12) - .andWhere('alternative_quest_reward_amount', amount) - .andWhere('alternative_quest_pokemon_id', pokeId) - }) + } else { + mega.andWhere(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'mega_resource' : 'info'}.pokemon_id") = ${pokeId}`)) + .andWhere(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'mega_resource' : 'info'}.amount") = ${amount}`)) } - } else { - questTypes.orWhere(mega => { - mega.where('quest_reward_type', 12) + }) + if (hasAltQuests) { + questTypes.orWhere(altMega => { + altMega.where('alternative_quest_reward_type', 12) if (hasRewardAmount) { - mega.andWhere('quest_reward_amount', amount) - .andWhere('quest_pokemon_id', pokeId) + altMega.andWhere('alternative_quest_reward_amount', amount) + .andWhere('alternative_quest_pokemon_id', pokeId) } else { - mega.andWhere(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'mega_resource' : 'info'}.pokemon_id") = ${pokeId}`)) - .andWhere(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'mega_resource' : 'info'}.amount") = ${amount}`)) + altMega.andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${pokeId}`)) + .andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.amount") = ${amount}`)) } }) - if (hasAltQuests) { - questTypes.orWhere(altMega => { - altMega.where('alternative_quest_reward_type', 12) - if (hasRewardAmount) { - altMega.andWhere('alternative_quest_reward_amount', amount) - .andWhere('alternative_quest_pokemon_id', pokeId) - } else { - altMega.andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${pokeId}`)) - .andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.amount") = ${amount}`)) - } - }) - } - } - }) - if (hasRewardAmount) { - questTypes.orWhere('quest_reward_type', 4) - .whereIn('quest_pokemon_id', candy) - if (hasAltQuests) { - questTypes.orWhere('alternative_quest_reward_type', 4) - .whereIn('alternative_quest_pokemon_id', candy) } - } else { - candy.forEach(poke => { - questTypes.orWhere(candies => { - candies.where('quest_reward_type', 4) - .where(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'candy' : 'info'}.pokemon_id") = ${poke}`)) - }) - if (hasAltQuests) { - questTypes.orWhere(altCandies => { - altCandies.where('alternative_quest_reward_type', 4) - .where(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${poke}`)) - }) - } - }) } - if (hasRewardAmount) { - questTypes.orWhere('quest_reward_type', 9) - .whereIn('quest_pokemon_id', xlCandy) + }) + if (hasRewardAmount) { + questTypes.orWhere('quest_reward_type', 4) + .whereIn('quest_pokemon_id', candy) + if (hasAltQuests) { + questTypes.orWhere('alternative_quest_reward_type', 4) + .whereIn('alternative_quest_pokemon_id', candy) + } + } else { + candy.forEach(poke => { + questTypes.orWhere(candies => { + candies.where('quest_reward_type', 4) + .where(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'candy' : 'info'}.pokemon_id") = ${poke}`)) + }) if (hasAltQuests) { - questTypes.orWhere('alternative_quest_reward_type', 9) - .whereIn('alternative_quest_pokemon_id', xlCandy) - } - } else { - xlCandy.forEach(poke => { - questTypes.orWhere(xlCandies => { - xlCandies.where('quest_reward_type', 9) - .where(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'xl_candy' : 'info'}.pokemon_id") = ${poke}`)) + questTypes.orWhere(altCandies => { + altCandies.where('alternative_quest_reward_type', 4) + .where(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${poke}`)) }) - if (hasAltQuests) { - questTypes.orWhere(altXlCandies => { - altXlCandies.where('alternative_quest_reward_type', 9) - .where(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${poke}`)) - }) - } - }) + } + }) + } + if (hasRewardAmount) { + questTypes.orWhere('quest_reward_type', 9) + .whereIn('quest_pokemon_id', xlCandy) + if (hasAltQuests) { + questTypes.orWhere('alternative_quest_reward_type', 9) + .whereIn('alternative_quest_pokemon_id', xlCandy) } - if (general.length && map.enableQuestRewardTypeFilters) { - questTypes.orWhere(rewardType => { - rewardType.whereIn('quest_reward_type', general) + } else { + xlCandy.forEach(poke => { + questTypes.orWhere(xlCandies => { + xlCandies.where('quest_reward_type', 9) + .where(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'xl_candy' : 'info'}.pokemon_id") = ${poke}`)) }) if (hasAltQuests) { - questTypes.orWhere(altRewardType => { - altRewardType.whereIn('alternative_quest_reward_type', general) + questTypes.orWhere(altXlCandies => { + altXlCandies.where('alternative_quest_reward_type', 9) + .where(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${poke}`)) }) } + }) + } + if (general.length && map.enableQuestRewardTypeFilters) { + questTypes.orWhere(rewardType => { + rewardType.whereIn('quest_reward_type', general) + }) + if (hasAltQuests) { + questTypes.orWhere(altRewardType => { + altRewardType.whereIn('alternative_quest_reward_type', general) + }) } - }) + } + }) }) } if (onlyInvasions && invasionPerms) { diff --git a/server/src/services/DbCheck.js b/server/src/services/DbCheck.js index d362fe89a..ddc46c125 100644 --- a/server/src/services/DbCheck.js +++ b/server/src/services/DbCheck.js @@ -3,7 +3,7 @@ const knex = require('knex') const { raw } = require('objection') module.exports = class DbCheck { - constructor(validModels, dbSettings, queryDebug, apiSettings) { + constructor(validModels, dbSettings, queryDebug, apiSettings, distanceUnit) { this.validModels = validModels.flatMap(s => s.useFor) this.singleModels = ['User', 'Badge', 'Session'] this.searchLimit = apiSettings.searchLimit @@ -36,10 +36,11 @@ module.exports = class DbCheck { }, }) }) + this.distanceUnit = distanceUnit } - static getDistance(args, isMad) { - return 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') + static getDistance(args, isMad, distanceUnit) { + return raw(`ROUND(( ${distanceUnit === 'mi' ? '3959' : '6371'} * 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') } async determineType() { @@ -136,7 +137,7 @@ module.exports = class DbCheck { async search(model, perms, args, method = 'search') { const data = await Promise.all(this.models[model].map(async (source) => ( - source.SubModel[method](perms, args, source, DbCheck.getDistance(args, source.isMad)) + source.SubModel[method](perms, args, source, DbCheck.getDistance(args, source.isMad, this.distanceUnit)) ))) const deDuped = DbCheck.deDupeResults(data).sort((a, b) => a.distance - b.distance) if (deDuped.length > this.searchLimit) { diff --git a/server/src/services/checkForUpdates.js b/server/src/services/checkForUpdates.js index 4d9783e2d..a3799d71b 100644 --- a/server/src/services/checkForUpdates.js +++ b/server/src/services/checkForUpdates.js @@ -6,7 +6,7 @@ const fs = require('fs') let isDocker = false try { - exec('git branch --show-current', async (err, stdout) => { + exec('git branch --show-current', (err, stdout) => { try { const gitRef = fs.readFileSync(path.resolve(`${__dirname}/../../../.gitref`), 'utf8') @@ -20,12 +20,12 @@ try { ? gitRef.split('/')[2].trim() : stdout.trim() - exec('git rev-parse HEAD', async (err2, stdout2) => { + exec('git rev-parse HEAD', (err2, stdout2) => { try { const gitSha = fs.readFileSync(path.resolve(`${__dirname}/../../../.gitsha`), 'utf8') if (!gitSha && (err2 || typeof stdout2 !== 'string' || !stdout2.trim())) { - throw new Error('Unable to get current sha', err) + throw new Error('Unable to get current sha', err2) } const sha = typeof gitSha === 'string' && gitSha.trim() ? gitSha.trim() diff --git a/server/src/services/config.js b/server/src/services/config.js index 09649404b..2808cf486 100644 --- a/server/src/services/config.js +++ b/server/src/services/config.js @@ -145,7 +145,9 @@ if (hasLittle) { } if (!config.authentication.strategies.length || !config.authentication.strategies.find(strategy => strategy.enabled)) { - config.authentication.alwaysEnabledPerms = Object.keys(config.authentication.perms) + const enabled = Object.keys(config.authentication.perms).filter(perm => config.authentication.perms[perm].enabled) + console.warn('[CONFIG] No authentication strategies enabled, adding the following perms to alwaysEnabledPerms array:\n', enabled) + config.authentication.alwaysEnabledPerms = enabled } // Map manual areas diff --git a/server/src/services/initialization.js b/server/src/services/initialization.js index f80ce6b51..bc1166c8a 100644 --- a/server/src/services/initialization.js +++ b/server/src/services/initialization.js @@ -8,8 +8,7 @@ const staticMf = require('../data/masterfile.json') const DbCheck = require('./DbCheck') const EventManager = require('./EventManager') const PvpWrapper = require('./PvpWrapper') - -const Db = new DbCheck(exampleSchemas, config.database, config.devOptions.queryDebug, config.api) +const Db = new DbCheck(exampleSchemas, config.database, config.devOptions.queryDebug, config.api, config.map.distanceUnit) const Pvp = config.api.pvp.reactMapHandlesPvp ? new PvpWrapper(config.api.pvp) : null const Event = new EventManager(staticMf) diff --git a/server/src/services/ui/clientOptions.js b/server/src/services/ui/clientOptions.js index 0dc12e8f8..7ffc9f5b5 100644 --- a/server/src/services/ui/clientOptions.js +++ b/server/src/services/ui/clientOptions.js @@ -43,9 +43,18 @@ module.exports = function clientOptions(perms) { clustering: { type: 'bool', perm: ['portals'] }, oldPortals: { type: 'color', perm: ['portals'] }, newPortals: { type: 'color', perm: ['portals'] }, + oneStopTillNext: { type: 'color', perm: ['submissionCells'] }, + twoStopsTillNext: { type: 'color', perm: ['submissionCells'] }, + noMoreGyms: { type: 'color', perm: ['submissionCells'] }, + lightMapBorder: { type: 'color', perm: ['submissionCells'] }, + darkMapBorder: { type: 'color', perm: ['submissionCells'] }, + cellBlocked: { type: 'color', perm: ['submissionCells'] }, + poiColor: { type: 'color', perm: ['submissionCells'] }, }, weather: { clickableIcon: { type: 'bool', perm: ['weather'] }, + lightMapBorder: { type: 'color', perm: ['weather'] }, + darkMapBorder: { type: 'color', perm: ['weather'] }, }, } diff --git a/src/components/Map.jsx b/src/components/Map.jsx index 1aa65cf36..114259bc0 100644 --- a/src/components/Map.jsx +++ b/src/components/Map.jsx @@ -179,7 +179,7 @@ export default function Map({ serverSettings: Utility.analytics('Data', `${category} being fetched`, category, true) return ( x ? x.size : 'md').join(',') : 'md'} bounds={Utility.getQueryArgs(map)} setExcludeList={setExcludeList} diff --git a/src/components/layout/dialogs/Search.jsx b/src/components/layout/dialogs/Search.jsx index 1a0717e37..d52ceb0a8 100644 --- a/src/components/layout/dialogs/Search.jsx +++ b/src/components/layout/dialogs/Search.jsx @@ -192,7 +192,7 @@ export default function Search({ )} - {option.distance}{t('km')} + {option.distance} {map.distanceUnit === 'mi' ? t('mi') : t('km')}
{safeSearch[searchTab] === 'quests' && ( diff --git a/src/components/layout/dialogs/UserOptions.jsx b/src/components/layout/dialogs/UserOptions.jsx index 295da34a8..55b9df4b0 100644 --- a/src/components/layout/dialogs/UserOptions.jsx +++ b/src/components/layout/dialogs/UserOptions.jsx @@ -101,7 +101,7 @@ export default function UserOptions({ category, toggleDialog, isMobile }) { action={toggleDialog(false, category, 'options')} /> - {category === 'pokemon' && ( + {tabPages.length > 1 && ( = 20) { return { - fillColor: 'black', color, opacity: 0.75, fillOpacity: 0.25, weight: 0.8, + fillColor: userSettings.noMoreGyms, color, opacity: 0.75, fillOpacity: 0.25, weight: 0.8, } } - return { - fillColor: 'blue', color, opacity: 0.75, fillOpacity: 0.0, weight: 0.8, - } + return { color, opacity: 0.75, fillOpacity: 0.0, weight: 0.8 } } diff --git a/src/components/popups/Pokestop.jsx b/src/components/popups/Pokestop.jsx index e66198deb..2e61bc878 100644 --- a/src/components/popups/Pokestop.jsx +++ b/src/components/popups/Pokestop.jsx @@ -102,7 +102,6 @@ export default function PokestopPopup({ t={t} /> { +const QuestConditions = ({ quest, t, userSettings }) => { const { i18n } = useTranslation() const { quest_task, @@ -421,11 +420,6 @@ const QuestConditions = ({ pokestop, quest, t, userSettings }) => { {{ categories: qInfo.character_category_ids.map(id => t(`character_category_${id}`)) }} ) - case 42: return ( - - {{ poi: pokestop.name }} - - ) case 44: return ( {{ time: qInfo.time }} diff --git a/src/components/tiles/Timer.jsx b/src/components/tiles/Timer.jsx index 15ea010ea..d912f6a47 100644 --- a/src/components/tiles/Timer.jsx +++ b/src/components/tiles/Timer.jsx @@ -24,7 +24,7 @@ const Timer = ({ timestamp }) => { export default function TooltipWrapper({ timers, offset }) { return ( - {timers.map((timer, i) => ( + {[...new Set(timers)].map((timer, i) => ( // eslint-disable-next-line react/no-array-index-key 1} /> ))} diff --git a/src/components/tiles/Weather.jsx b/src/components/tiles/Weather.jsx index 63efe15fd..21d9671f3 100644 --- a/src/components/tiles/Weather.jsx +++ b/src/components/tiles/Weather.jsx @@ -4,7 +4,7 @@ import { Popup, Polyline, Marker } from 'react-leaflet' import weatherMarker from '../markers/weather' import PopupContent from '../popups/Weather' -const WeatherTile = ({ item, ts, Icons, isNight, tileStyle }) => { +const WeatherTile = ({ item, ts, Icons, isNight, tileStyle, userSettings }) => { const [popup, setPopup] = useState(false) const markerRef = useRef(null) @@ -18,10 +18,10 @@ const WeatherTile = ({ item, ts, Icons, isNight, tileStyle }) => { { const areEqual = (prev, next) => ( prev.item.gameplay_condition === next.item.gameplay_condition && prev.item.updated === next.item.updated + && prev.tileStyle === next.tileStyle ) export default memo(WeatherTile, areEqual) diff --git a/src/components/tiles/submissionCells/Placement.jsx b/src/components/tiles/submissionCells/Placement.jsx index 124dc836c..193757745 100644 --- a/src/components/tiles/submissionCells/Placement.jsx +++ b/src/components/tiles/submissionCells/Placement.jsx @@ -3,10 +3,10 @@ import { Polygon } from 'react-leaflet' import placementStyle from '../../markers/placementCell' -const PlacementTile = ({ cell, tileStyle }) => ( +const PlacementTile = ({ cell, tileStyle, userSettings }) => ( ) @@ -14,6 +14,7 @@ const PlacementTile = ({ cell, tileStyle }) => ( const areEqual = (prev, next) => ( prev.cell.id === next.cell.id && prev.zoom === next.zoom + && prev.tileStyle === next.tileStyle ) export default memo(PlacementTile, areEqual) diff --git a/src/components/tiles/submissionCells/Ring.jsx b/src/components/tiles/submissionCells/Ring.jsx index f2be9932e..b19f3a9d9 100644 --- a/src/components/tiles/submissionCells/Ring.jsx +++ b/src/components/tiles/submissionCells/Ring.jsx @@ -1,18 +1,17 @@ import React, { memo } from 'react' import { Circle } from 'react-leaflet' -const RingTile = ({ ring }) => ( +const RingTile = ({ ring, userSettings }) => ( ) const areEqual = (prev, next) => ( prev.ring.id === next.ring.id - && prev.ring.lat === next.ring.lat - && prev.ring.lon === next.ring.lon && prev.zoom === next.zoom ) diff --git a/src/components/tiles/submissionCells/SubmissionCell.jsx b/src/components/tiles/submissionCells/SubmissionCell.jsx index fafff6046..8fa31f1cc 100644 --- a/src/components/tiles/submissionCells/SubmissionCell.jsx +++ b/src/components/tiles/submissionCells/SubmissionCell.jsx @@ -4,7 +4,7 @@ import PlacementTile from './Placement' import RingTile from './Ring' export default function SubmissionCellTile({ - item, tileStyle, config, zoom, + item, tileStyle, config, zoom, userSettings, }) { const zoomLimit = zoom >= config.submissionZoom return zoom >= (config.submissionZoom - 1) && ( @@ -15,6 +15,7 @@ export default function SubmissionCellTile({ key={ring.id} ring={ring} zoom={zoomLimit} + userSettings={userSettings} /> ))} {(item?.placementCells?.cells && zoomLimit) @@ -24,6 +25,7 @@ export default function SubmissionCellTile({ cell={cell} tileStyle={tileStyle} zoom={zoomLimit} + userSettings={userSettings} /> ))} {item?.typeCells && item.typeCells.map(cell => ( @@ -32,6 +34,7 @@ export default function SubmissionCellTile({ cell={cell} tileStyle={tileStyle} zoom={zoom >= (config.submissionZoom - 1)} + userSettings={userSettings} /> ))} diff --git a/src/components/tiles/submissionCells/Type.jsx b/src/components/tiles/submissionCells/Type.jsx index 1a19c3ac8..3a2ed2012 100644 --- a/src/components/tiles/submissionCells/Type.jsx +++ b/src/components/tiles/submissionCells/Type.jsx @@ -4,10 +4,10 @@ import { Polygon, Popup, Tooltip } from 'react-leaflet' import PopupContent from '../../popups/SubmissionCell' import typeStyle from '../../markers/typeCell' -const TypeTile = ({ cell, tileStyle }) => ( +const TypeTile = ({ cell, tileStyle, userSettings }) => ( ( prev.cell.id === next.cell.id && prev.cell.count === next.cell.count && prev.zoom === next.zoom + && prev.tileStyle === next.tileStyle ) export default memo(TypeTile, areEqual)