Skip to content

Release - 2025 July #1040

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
Jul 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d3d9213
feat: osm auth for web client
ofr1tz May 8, 2025
2885ddc
fix: use web redirect uri in token_web
ofr1tz May 8, 2025
f5f0c61
fix: adapt firebase.json for web app osm login
ofr1tz May 8, 2025
c259519
fix: osm oauth app login link env variable
ofr1tz May 14, 2025
b006d8b
fix: avoid underscore in fb function names
ofr1tz May 15, 2025
e2c22ba
fix: add doc
ofr1tz May 15, 2025
2615331
refactor: redirect and token
ofr1tz May 19, 2025
515190c
fix: pass req res admin
ofr1tz May 19, 2025
52a0054
style: remove blank line padding
ofr1tz May 19, 2025
e04f694
fix: typing
ofr1tz May 19, 2025
3944e67
fix: remove space before ,
ofr1tz May 19, 2025
95d0c56
fix: avoid overwriting existing osm profiles on sign in
ofr1tz May 20, 2025
29ce576
revert change to requirements
ofr1tz May 20, 2025
57385ef
fix: clean parentheses
ofr1tz May 20, 2025
a8d0ae6
fix: formatting
ofr1tz May 20, 2025
a8c662b
fix: use once instead of get
ofr1tz May 20, 2025
0aace7f
reuse profileRef and add semicolons
ofr1tz May 20, 2025
bbfb5ad
fix: add arg to once
ofr1tz May 20, 2025
09a955d
add logging
ofr1tz May 20, 2025
61bb66e
fix: use singlequote
ofr1tz May 21, 2025
85710d5
move profile tasks definition
ofr1tz May 21, 2025
3430784
fix indentation
ofr1tz May 21, 2025
ed806f6
fix: clean up
ofr1tz May 21, 2025
a758dc1
docs(osm-login-web): add web osm login to docs
ofr1tz May 21, 2025
8b4941f
Merge branch 'dev' into osm-login-web
ofr1tz May 22, 2025
9380c13
Merge pull request #1031 from mapswipe/osm-login-web
ofr1tz Jun 3, 2025
d256198
fix(sql): fix typo in comment in initdb.sql
thenav56 Jun 12, 2025
d4805a0
feat(django): add support for unaccent search for usergroups
thenav56 Jun 12, 2025
8f663c7
Merge pull request #1035 from mapswipe/feat/unaccent-usergroup-search
thenav56 Jun 12, 2025
4242d7b
feat(validate_image): add validate image project & tutorial creation
tnagorra Jun 26, 2025
c28bea1
fix(docker-compose): add mapillary_api_key in tc docker compose
tnagorra Jun 26, 2025
3fb2aa2
feat(validate_image): update form for validate image project & tutori…
tnagorra Jun 26, 2025
fa13b4f
feat(validate_image): validations for coco file
tnagorra Jun 27, 2025
d769ac8
feat(validate_image): add scripts to generate coco files
tnagorra Jun 27, 2025
c1c5bb4
feat(validate_image): add validate image updates in community dashboard
AdityaKhatri Jul 8, 2025
62b3f1a
feat(aggregates): update aggregates for validate image project
tnagorra Jul 11, 2025
7385edf
chore(ci): Build docker images before-hand
tnagorra Jul 13, 2025
1371c5d
feat(validate_image): add validate image swipes count in stats group
AdityaKhatri Jul 14, 2025
74a7743
Merge pull request #1038 from mapswipe/feature/validate-image-proj
AdityaKhatri Jul 14, 2025
62d87b8
Merge branch 'main' into dev
AdityaKhatri Jul 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,28 @@ jobs:
exit 1;
}

- name: Decrypt Service Account Key File
working-directory: ./
run: |
openssl enc -aes-256-cbc -d -K "$OPENSSL_KEY" -iv "$OPENSSL_IV" -in ci-mapswipe-firebase-adminsdk-80fzw-ebce84bd5b.json.enc -out mapswipe_workers/serviceAccountKey.json
env:
OPENSSL_PASSPHRASE: ${{ secrets.OPENSSL_PASSPHRASE }}
OPENSSL_KEY: ${{ secrets.OPENSSL_KEY }}
OPENSSL_IV: ${{ secrets.OPENSSL_IV }}

- name: Build docker images
run: |
# Create a mock file for wal-g setup
touch postgres/serviceAccountKey.json
docker compose build postgres firebase_deploy mapswipe_workers_creation django

- name: Setup Postgres Database Container
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: postgres
run: |
# Create a mock file for wal-g setup
touch postgres/serviceAccountKey.json
docker compose up --build --detach postgres
docker compose up --detach postgres
for i in {1..5}; do docker compose exec -T postgres pg_isready && s=0 && break || s=$? && sleep 5; done; (docker compose logs postgres && exit $s)

- name: Deploy Firebase Rules and Functions
Expand All @@ -60,15 +73,6 @@ jobs:
run: |
docker compose run --rm firebase_deploy sh -c "firebase use $FIREBASE_DB && firebase deploy --token $FIREBASE_TOKEN --only database"

- name: Decrypt Service Account Key File
working-directory: ./
run: |
openssl enc -aes-256-cbc -d -K "$OPENSSL_KEY" -iv "$OPENSSL_IV" -in ci-mapswipe-firebase-adminsdk-80fzw-ebce84bd5b.json.enc -out mapswipe_workers/serviceAccountKey.json
env:
OPENSSL_PASSPHRASE: ${{ secrets.OPENSSL_PASSPHRASE }}
OPENSSL_KEY: ${{ secrets.OPENSSL_KEY }}
OPENSSL_IV: ${{ secrets.OPENSSL_IV }}

- name: Run Tests
working-directory: ./mapswipe_workers
env:
Expand Down
13 changes: 13 additions & 0 deletions community-dashboard/app/resources/icons/validate-image.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 55 additions & 9 deletions community-dashboard/app/views/StatsBoard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ import InformationCard from '#components/InformationCard';
import areaSvg from '#resources/icons/area.svg';
import sceneSvg from '#resources/icons/scene.svg';
import featureSvg from '#resources/icons/feature.svg';
import validateImageSvg from '#resources/icons/validate-image.svg';
import {
ContributorTimeStatType,
OrganizationSwipeStatsType,
ProjectTypeSwipeStatsType,
ProjectTypeAreaStatsType,
ContributorSwipeStatType,
ProjectTypeEnum,
} from '#generated/types';
import { mergeItems } from '#utils/common';
import {
Expand All @@ -67,17 +69,28 @@ const CHART_BREAKPOINT = 700;
export type ActualContributorTimeStatType = ContributorTimeStatType & { totalSwipeTime: number };
const UNKNOWN = '-1';
const BUILD_AREA = 'BUILD_AREA';
const MEDIA = 'MEDIA';
const DIGITIZATION = 'DIGITIZATION';
const FOOTPRINT = 'FOOTPRINT';
const CHANGE_DETECTION = 'CHANGE_DETECTION';
const VALIDATE_IMAGE = 'VALIDATE_IMAGE';
const COMPLETENESS = 'COMPLETENESS';
const STREET = 'STREET';

// FIXME: the name property is not used properly
const projectTypes: Record<string, { color: string, name: string }> = {
const projectTypes: Record<ProjectTypeEnum | '-1', { color: string, name: string }> = {
[UNKNOWN]: {
color: '#cacaca',
name: 'Unknown',
},
[MEDIA]: {
color: '#cacaca',
name: 'Media',
},
[DIGITIZATION]: {
color: '#cacaca',
name: 'Digitization',
},
[BUILD_AREA]: {
color: '#f8a769',
name: 'Find',
Expand All @@ -94,6 +107,10 @@ const projectTypes: Record<string, { color: string, name: string }> = {
color: '#fb8072',
name: 'Completeness',
},
[VALIDATE_IMAGE]: {
color: '#a1b963',
name: 'Validate Image',
},
[STREET]: {
color: '#808080',
name: 'Street',
Expand Down Expand Up @@ -376,14 +393,16 @@ function StatsBoard(props: Props) {
const sortedProjectSwipeType = useMemo(
() => (
swipeByProjectType
?.map((item) => ({
...item,
projectType: (
isDefined(item.projectType)
&& isDefined(projectTypes[item.projectType])
) ? item.projectType
: UNKNOWN,
}))
?.map((item) => {
const projectType: ProjectTypeEnum | '-1' = (
isDefined(item.projectType) && isDefined(projectTypes[item.projectType])
) ? item.projectType : UNKNOWN;

return ({
...item,
projectType,
});
})
.sort((a, b) => compareNumber(a.totalSwipes, b.totalSwipes, -1)) ?? []
),
[swipeByProjectType],
Expand Down Expand Up @@ -449,6 +468,10 @@ function StatsBoard(props: Props) {
(project) => project.projectType === FOOTPRINT,
)?.totalSwipes;

const validateImageTotalSwipes = swipeByProjectType?.find(
(project) => project.projectType === VALIDATE_IMAGE,
)?.totalSwipes;

const organizationColors = scaleOrdinal<string, string | undefined>()
.domain(totalSwipesByOrganizationStats?.map(
(organization) => (organization.organizationName),
Expand Down Expand Up @@ -699,6 +722,29 @@ function StatsBoard(props: Props) {
subHeading="Compare"
variant="stat"
/>
<InformationCard
icon={(
<img
src={validateImageSvg}
alt="group icon"
/>
)}
value={(
<NumberOutput
className={styles.numberOutput}
value={validateImageTotalSwipes}
normal
invalidText={0}
/>
)}
label={(
<div className={styles.infoLabel}>
Images Validated
</div>
)}
subHeading="Validate Image"
variant="stat"
/>
</div>
<div className={styles.overallStatsContainer}>
<InformationCard
Expand Down
2 changes: 1 addition & 1 deletion community-dashboard/app/views/StatsBoard/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
>* {
flex-basis: 0;
flex-grow: 1;
min-width: 12rem;
min-width: 24rem;

@media (max-width: 48rem) {
min-width: 100%;
Expand Down
3 changes: 1 addition & 2 deletions community-dashboard/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ version: '3.3'

services:
react:
build: .
command: sh -c 'yarn install --frozen-lockfile && yarn start'
build:
context: ./
Expand All @@ -15,4 +14,4 @@ services:
volumes:
- .:/code
ports:
- '3080:3080'
- '3081:3081'
2 changes: 1 addition & 1 deletion django/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.10-buster
FROM python:3.10-bullseye

LABEL maintainer="Mapswipe info@mapswipe.org"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
WHEN P.project_type = {Project.Type.CHANGE_DETECTION.value} THEN 11.2
-- FOOTPRINT: Not calculated right now
WHEN P.project_type = {Project.Type.FOOTPRINT.value} THEN 6.1
WHEN P.project_type = {Project.Type.VALIDATE_IMAGE.value} THEN 6.1
WHEN P.project_type = {Project.Type.STREET.value} THEN 65
ELSE 1
END
Expand Down Expand Up @@ -111,6 +112,7 @@
WHEN P.project_type = {Project.Type.CHANGE_DETECTION.value} THEN 11.2
-- FOOTPRINT: Not calculated right now
WHEN P.project_type = {Project.Type.FOOTPRINT.value} THEN 6.1
WHEN P.project_type = {Project.Type.VALIDATE_IMAGE.value} THEN 6.1
WHEN P.project_type = {Project.Type.STREET.value} THEN 65
ELSE 1
END
Expand All @@ -136,8 +138,10 @@
G.group_id,
(
CASE
-- Hide area for Footprint
-- Hide area for Footprint and Validate Image
-- FIXME: What should we do for Project.Type.STREET.value
WHEN P.project_type = {Project.Type.FOOTPRINT.value} THEN 0
WHEN P.project_type = {Project.Type.VALIDATE_IMAGE.value} THEN 0
ELSE G.total_area
END
) as total_task_group_area,
Expand Down
1 change: 1 addition & 0 deletions django/apps/existing_database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class Type(models.IntegerChoices):
MEDIA = 5, "Media"
DIGITIZATION = 6, "Digitization"
STREET = 7, "Street"
VALIDATE_IMAGE = 10, "Validate Image"

project_id = models.CharField(primary_key=True, max_length=999)
created = models.DateTimeField(blank=True, null=True)
Expand Down
1 change: 1 addition & 0 deletions django/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ enum ProjectTypeEnum {
MEDIA
DIGITIZATION
STREET
VALIDATE_IMAGE
}

type ProjectTypeSwipeStatsType {
Expand Down
1 change: 1 addition & 0 deletions docker-compose.tc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ x-mapswipe-workers: &base_mapswipe_workers
SLACK_CHANNEL: '${SLACK_CHANNEL}'
SENTRY_DSN: '${SENTRY_DSN}'
OSMCHA_API_KEY: '${OSMCHA_API_KEY}'
MAPILLARY_API_KEY: '${MAPILLARY_API_KEY}'
depends_on:
- postgres
volumes:
Expand Down
10 changes: 9 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,23 @@ services:
OSM_OAUTH_API_URL: '${OSM_OAUTH_API_URL}'
OSM_OAUTH_CLIENT_ID: '${OSM_OAUTH_CLIENT_ID}'
OSM_OAUTH_CLIENT_SECRET: '${OSM_OAUTH_CLIENT_SECRET}'
OSM_OAUTH_REDIRECT_URI_WEB: '${OSM_OAUTH_REDIRECT_URI_WEB}'
OSM_OAUTH_APP_LOGIN_LINK_WEB: '${OSM_OAUTH_APP_LOGIN_LINK_WEB}'
OSM_OAUTH_CLIENT_ID_WEB: '${OSM_OAUTH_CLIENT_ID_WEB}'
OSM_OAUTH_CLIENT_SECRET_WEB: '${OSM_OAUTH_CLIENT_SECRET_WEB}'
command: >-
sh -c "firebase use $FIREBASE_DB &&
firebase target:apply hosting auth \"$FIREBASE_AUTH_SITE\" &&
firebase functions:config:set
osm.redirect_uri=\"$OSM_OAUTH_REDIRECT_URI\"
osm.redirect_uri_web=\"$OSM_OAUTH_REDIRECT_URI_WEB\"
osm.app_login_link=\"$OSM_OAUTH_APP_LOGIN_LINK\"
osm.app_login_link_web=\"$OSM_OAUTH_APP_LOGIN_LINK_WEB\"
osm.api_url=\"$OSM_OAUTH_API_URL\"
osm.client_id=\"$OSM_OAUTH_CLIENT_ID\"
osm.client_secret=\"$OSM_OAUTH_CLIENT_SECRET\" &&
osm.client_id_web=\"$OSM_OAUTH_CLIENT_ID_WEB\"
osm.client_secret=\"$OSM_OAUTH_CLIENT_SECRET\"
osm.client_secret_web=\"$OSM_OAUTH_CLIENT_SECRET_WEB\" &&
firebase deploy --token $FIREBASE_TOKEN --only functions,hosting,database"

django:
Expand Down
7 changes: 6 additions & 1 deletion example.env
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,15 @@ OSMCHA_API_KEY=

# OSM OAuth Configuration
OSM_OAUTH_REDIRECT_URI=
OSM_OAUTH_REDIRECT_URI_WEB=
OSM_OAUTH_API_URL=
OSM_OAUTH_CLIENT_ID=
OSM_OAUTH_CLIENT_ID_WEB=
OSM_OAUTH_CLIENT_SECRET=
OSM_APP_LOGIN_LINK=
OSM_OAUTH_CLIENT_SECRET_WEB=
OSM_OAUTH_APP_LOGIN_LINK=
OSM_OAUTH_APP_LOGIN_LINK_WEB=


# DJANGO For more info look at django/mapswipe/settings.py::L22
DJANGO_SECRET_KEY=
Expand Down
9 changes: 9 additions & 0 deletions firebase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ expose the authentication functions publicly.
* `firebase deploy --only functions,hosting`
* `firebase deploy --only database:rules`

## Deploy with Makefile
You can also deploy the changes to Firebase using make:
* Make sure to remove the firebase_deploy docker image first: `docker rmi python-mapswipe-workers-firebase_deploy`
* `make update_firebase_functions_and_db_rules`

## Notes on OAuth (OSM login)

Refer to [the notes in the app repository](https://github.com/mapswipe/mapswipe/blob/master/docs/osm_login.md).
Expand All @@ -30,12 +35,16 @@ Some specifics about the related functions:
- Before deploying, set the required firebase config values in environment:
FIXME: replace env vars with config value names
- OSM_OAUTH_REDIRECT_URI `osm.redirect_uri`: `https://dev-auth.mapswipe.org/token` or `https://auth.mapswipe.org/token`
- OSM_OAUTH_REDIRECT_URI_WEB: `https://dev-auth.mapswipe.org/tokenweb` or `https://auth.mapswipe.org/tokenweb`
- OSM_OAUTH_APP_LOGIN_LINK `osm.app_login_link`: 'devmapswipe://login/osm' or 'mapswipe://login/osm'
- OSM_OAUTH_APP_LOGIN_LINK_WEB: `https://web.mapswipe.org/dev/#/osm-callback` or `https://web.mapswipe.org/#/osm-callback`
- OSM_OAUTH_API_URL `osm.api_url`: 'https://master.apis.dev.openstreetmap.org/' or 'https://www.openstreetmap.org/' (include the
trailing slash)
- OSM_OAUTH_CLIENT_ID `osm.client_id`: find it on the OSM application page
- OSM_OAUTH_CLIENT_SECRET `osm.client_secret`: same as above. Note that this can only be seen once when the application is created. Do not
lose it!
- OSM_OAUTH_CLIENT_ID_WEB: This is the ID of a __different__ registered OSM OAuth client for the web version that needs to have `https://dev-auth.mapswipe.org/tokenweb` or `https://auth.mapswipe.org/tokenweb` set as redirect URI.
- OSM_OAUTH_CLIENT_SECRET_WEB: This is the secret of the OSM OAuth client for MapSwipe web version.
- Deploy the functions as explained above
- Expose the functions publicly through firebase hosting, this is done in `/firebase/firebase.json` under the `hosting`
key.
Expand Down
8 changes: 8 additions & 0 deletions firebase/firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
{
"source": "/token",
"function": "osmAuth-token"
},
{
"source": "/redirectweb",
"function": "osmAuth-redirectweb"
},
{
"source": "/tokenweb",
"function": "osmAuth-tokenweb"
}
]
},
Expand Down
10 changes: 9 additions & 1 deletion firebase/functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ admin.initializeApp();
// all functions are bundled together. It's less than ideal, but it does not
// seem possible to split them using the split system for multiple sites from
// https://firebase.google.com/docs/hosting/multisites
import {redirect, token} from './osm_auth';
import {redirect, token, redirectweb, tokenweb} from './osm_auth';
import { formatProjectTopic, formatUserName } from './utils';

exports.osmAuth = {};
Expand All @@ -23,6 +23,14 @@ exports.osmAuth.token = functions.https.onRequest((req, res) => {
token(req, res, admin);
});

exports.osmAuth.redirectweb = functions.https.onRequest((req, res) => {
redirectweb(req, res);
});

exports.osmAuth.tokenweb = functions.https.onRequest((req, res) => {
tokenweb(req, res, admin);
});

/*
Log the userIds of all users who finished a group to /v2/userGroups/{projectId}/{groupId}/.
Gets triggered when new results of a group are written to the database.
Expand Down
Loading
Loading