diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c7e63266c..bba06caa2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,6 +29,11 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} HUSKY: 0 run: npx semantic-release + - name: Configure git + if: ${{ github.ref_name == 'main'}} + run: | + git config --global user.name "turtlesocks-bot" + git config --global user.email "turtlesocks-bot@users.noreply.github.com" - name: Sync Dev to Main if: ${{ github.ref_name == 'main'}} env: diff --git a/CHANGELOG.md b/CHANGELOG.md index cd5b31f0e..230f0d171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,41 @@ +## [1.41.1](https://github.com/WatWowMap/ReactMap/compare/v1.41.0...v1.41.1) (2026-03-15) + + +### Bug Fixes + +* workflow git creds ([e5dc6f9](https://github.com/WatWowMap/ReactMap/commit/e5dc6f90d14fa1afb8a75bb9bdb2246213ff1c88)) + +# [1.41.0](https://github.com/WatWowMap/ReactMap/compare/v1.40.1...v1.41.0) (2026-03-15) + + +### Bug Fixes + +* area reload ([cea3141](https://github.com/WatWowMap/ReactMap/commit/cea3141386d804f502e83e89b9bf92da93102a5d)) +* battle/raid filtering race condition ([2a9cbbf](https://github.com/WatWowMap/ReactMap/commit/2a9cbbf180313064830a524f86eae62f41b6b87b)) +* battle/raid icon max height ([497f350](https://github.com/WatWowMap/ReactMap/commit/497f3504a4ea6000184c9df30c5a3c3e76d65d80)) +* ditto shenanigans ([#1193](https://github.com/WatWowMap/ReactMap/issues/1193)) ([647a175](https://github.com/WatWowMap/ReactMap/commit/647a1758e6c3ab0dc4340c7a4b6fe8cc88e00084)) +* escape gpx xml ([#1186](https://github.com/WatWowMap/ReactMap/issues/1186)) ([7bd5ce1](https://github.com/WatWowMap/ReactMap/commit/7bd5ce10d3e8aa6f64faac8d3d9773c589d6a28e)) +* ground raid/battle icons ([cd01a92](https://github.com/WatWowMap/ReactMap/commit/cd01a92bda81f786ca2c14f10df8cc4489163fd6)) +* hidden power in raids are fighting type ([018ba93](https://github.com/WatWowMap/ReactMap/commit/018ba93642eee0a08d2a864c1a04998ff63503a9)) +* im dumdum ([ce37e2a](https://github.com/WatWowMap/ReactMap/commit/ce37e2a9123ea2808cde3f3f130361055141ae63)) +* logic bug in loading non-clustered elements ([#1161](https://github.com/WatWowMap/ReactMap/issues/1161)) ([a2c7f17](https://github.com/WatWowMap/ReactMap/commit/a2c7f17e02ff7cd5467d4bf5ccd8b13a444ba725)) +* more robust discord handling ([#1181](https://github.com/WatWowMap/ReactMap/issues/1181)) ([b579ded](https://github.com/WatWowMap/ReactMap/commit/b579dedeb196fb4d8b1da025e325049bfd7833e8)) +* no scrollbars plz ([907ca33](https://github.com/WatWowMap/ReactMap/commit/907ca331beb1fe81dd671732d5ebe1980d8d6faa)) +* pokemon onlyManualId filter in expert sql mode ([ee176da](https://github.com/WatWowMap/ReactMap/commit/ee176da3749c27b33aa659ba432706ad5c19951b)) +* properly migrate to express 5 ([3907656](https://github.com/WatWowMap/ReactMap/commit/390765696dbdcd89ed2fd57b16d41ecc2725a1b9)) +* remove extra Forms ([0f157ed](https://github.com/WatWowMap/ReactMap/commit/0f157edba37eb727fdb9f4a5b96bdf417298cdfc)) +* sentry node version ([8640ee0](https://github.com/WatWowMap/ReactMap/commit/8640ee0da68cc2a23e4d12e472b109a6628507c6)) +* showcase icons display ([b626d3d](https://github.com/WatWowMap/ReactMap/commit/b626d3d37c18b5ef6261f02b105796fdb8ce011f)) +* weather icon in pokemon background popup ([21b50f5](https://github.com/WatWowMap/ReactMap/commit/21b50f51b81bf6f7723753a4f77289ead99c51e7)) + + +### Features + +* ar/no-ar quest dot badge ([8adba28](https://github.com/WatWowMap/ReactMap/commit/8adba286fea81d194e0dd4b7da5c680f6499b697)) +* default clientPrompt to none to skip permission reapproval ([d3ea283](https://github.com/WatWowMap/ReactMap/commit/d3ea283b5eacda18b9f4725e50e5353a955a363d)) +* dynamic placed Pokemon dropdown height ([8a0447c](https://github.com/WatWowMap/ReactMap/commit/8a0447c3e9d7df9c4aa9add657a234a1bc59b412)) +* support stationed pokemon extras ([4f5aace](https://github.com/WatWowMap/ReactMap/commit/4f5aace285285d55e3a946fb2f465b7609a9caea)) + # [1.41.0-develop.11](https://github.com/WatWowMap/ReactMap/compare/v1.41.0-develop.10...v1.41.0-develop.11) (2026-03-15) diff --git a/config/local.example.json b/config/local.example.json index 5f93a1674..b44e5a377 100644 --- a/config/local.example.json +++ b/config/local.example.json @@ -90,11 +90,13 @@ "areaRestrictions": [ { "roles": [], - "areas": [] + "areas": [], + "parent": [] }, { "roles": [], - "areas": [] + "areas": [], + "parent": [] } ], "aliases": [ diff --git a/package.json b/package.json index 7b9764019..0c4bac6ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "reactmap", - "version": "1.41.0-develop.11", + "version": "1.41.1", "private": true, "description": "React based frontend map.", "license": "MIT", diff --git a/packages/config/lib/mutations.js b/packages/config/lib/mutations.js index aad7c2c08..f18f87a04 100644 --- a/packages/config/lib/mutations.js +++ b/packages/config/lib/mutations.js @@ -307,9 +307,10 @@ const applyMutations = (config) => { }) config.authentication.areaRestrictions = - config.authentication.areaRestrictions.map(({ roles, areas }) => ({ + config.authentication.areaRestrictions.map(({ roles, areas, parent }) => ({ roles: roles.flatMap(replaceAliases), areas, + parent, })) config.authentication.strategies = config.authentication.strategies.map( diff --git a/packages/types/lib/config.d.ts b/packages/types/lib/config.d.ts index 4c098138e..e4747dc4d 100644 --- a/packages/types/lib/config.d.ts +++ b/packages/types/lib/config.d.ts @@ -53,7 +53,7 @@ export type Config = DeepMerge< } areas: ConfigAreas authentication: { - areaRestrictions: { roles: string[]; areas: string[] }[] + areaRestrictions: { roles: string[]; areas: string[]; parent?: string[] }[] // Unfortunately these types are not convenient for looping the `perms` object... // excludeFromTutorial: (keyof BaseConfig['authentication']['perms'])[] // alwaysEnabledPerms: (keyof BaseConfig['authentication']['perms'])[] diff --git a/server/src/graphql/resolvers.js b/server/src/graphql/resolvers.js index cf27d5fd8..ac4690796 100644 --- a/server/src/graphql/resolvers.js +++ b/server/src/graphql/resolvers.js @@ -362,6 +362,7 @@ const resolvers = { (feature) => !feature.properties.hidden && (!perms.areaRestrictions.length || + perms.areaRestrictions.includes(feature.properties.key) || perms.areaRestrictions.includes(feature.properties.name) || perms.areaRestrictions.includes(feature.properties.parent)), ), @@ -379,8 +380,11 @@ const resolvers = { ...parent, children: perms.areaRestrictions.includes(parent.name) ? parent.children - : parent.children.filter((child) => - perms.areaRestrictions.includes(child.properties.name), + : parent.children.filter( + (child) => + perms.areaRestrictions.includes(child.properties.key) || + perms.areaRestrictions.includes(child.properties.name) || + perms.areaRestrictions.includes(child.properties.parent), ), })) .filter((parent) => parent.children.length) diff --git a/server/src/utils/areaPerms.js b/server/src/utils/areaPerms.js index 596f239fe..fc3c2f5c4 100644 --- a/server/src/utils/areaPerms.js +++ b/server/src/utils/areaPerms.js @@ -9,20 +9,50 @@ function areaPerms(roles) { const areaRestrictions = config.getSafe('authentication.areaRestrictions') const areas = config.getSafe('areas') + // Map parent names to child keys for easy lookup when parent-based restrictions are used. + const parentKeyMap = Object.values(areas.scanAreasObj).reduce( + (acc, feature) => { + const { parent } = feature.properties + if (!parent) return acc + if (!acc[parent]) acc[parent] = [] + acc[parent].push(feature.properties.key) + return acc + }, + /** @type {Record} */ ({}), + ) + const perms = [] for (let i = 0; i < roles.length; i += 1) { for (let j = 0; j < areaRestrictions.length; j += 1) { - if (areaRestrictions[j].roles.includes(roles[i])) { - if (areaRestrictions[j].areas.length) { - for (let k = 0; k < areaRestrictions[j].areas.length; k += 1) { - if (areas.names.has(areaRestrictions[j].areas[k])) { - perms.push(areaRestrictions[j].areas[k]) - } else if (areas.withoutParents[areaRestrictions[j].areas[k]]) { - perms.push(...areas.withoutParents[areaRestrictions[j].areas[k]]) - } + if (!areaRestrictions[j].roles.includes(roles[i])) continue + + const hasAreas = Array.isArray(areaRestrictions[j].areas) + ? areaRestrictions[j].areas.length > 0 + : false + const hasParents = Array.isArray(areaRestrictions[j].parent) + ? areaRestrictions[j].parent.length > 0 + : false + + // No areas/parents means unrestricted access + if (!hasAreas && !hasParents) return [] + + if (hasAreas) { + for (let k = 0; k < areaRestrictions[j].areas.length; k += 1) { + const target = areaRestrictions[j].areas[k] + if (areas.names.has(target)) { + perms.push(target) + } else if (areas.withoutParents[target]) { + perms.push(...areas.withoutParents[target]) } - } else { - return [] + } + } + + if (hasParents) { + for (let k = 0; k < areaRestrictions[j].parent.length; k += 1) { + const parent = areaRestrictions[j].parent[k] + // If the parent itself exists as a top-level area, allow it too. + if (areas.names.has(parent)) perms.push(parent) + if (parentKeyMap[parent]) perms.push(...parentKeyMap[parent]) } } } diff --git a/src/features/drawer/areas/Child.jsx b/src/features/drawer/areas/Child.jsx index a22f72aa8..fd561b3c4 100644 --- a/src/features/drawer/areas/Child.jsx +++ b/src/features/drawer/areas/Child.jsx @@ -103,15 +103,17 @@ export function AreaChild({ indeterminate={name ? hasSome && !hasAll : false} checked={name ? hasAll : scanAreas.includes(feature.properties.key)} onClick={(e) => e.stopPropagation()} - onChange={() => - setAreas( - name - ? childAreas.map((c) => c.properties.key) - : feature.properties.key, - allAreas, - name ? hasSome : false, - ) - } + onChange={() => { + const areaKeys = name + ? [ + ...(feature?.properties?.key + ? [feature.properties.key] + : []), + ...childAreas.map((c) => c.properties.key), + ] + : feature.properties.key + setAreas(areaKeys, allAreas, name ? hasSome : false) + }} sx={{ p: 1, color,