Skip to content

Commit 65d942f

Browse files
authored
Merge branch 'develop' into web/task/display-name-validation
2 parents 31bf7bb + 73ddf89 commit 65d942f

66 files changed

Lines changed: 2317 additions & 508 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
pyrightconfig.json
1111

1212
/private/
13-
.claude/*
14-
!.claude/tools/
15-
!.claude/tools/**
13+
**/.claude/*
14+
!/.claude/tools/
15+
!/.claude/tools/**

app/.gitlab-ci.yml

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -456,25 +456,24 @@ test:media:
456456
test:web:
457457
needs: ["build:web-dev"]
458458
stage: test
459+
parallel: 3
459460
image: $WEB_DEV_TAG
460461
inherit:
461462
# no docker login
462463
default: false
464+
variables:
465+
NEXT_PUBLIC_API_BASE_URL: "http://localhost:8888"
466+
TZ: "UTC"
463467
script:
464-
- cd /app && yarn test-ci
468+
- cd /app && yarn jest --runInBand --coverage --coverageDirectory=coverage-$CI_NODE_INDEX --reporters="default" --reporters="jest-junit" --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
465469
after_script:
466-
- cp /app/junit.xml $CI_PROJECT_DIR/
467-
- cp /app/coverage/cobertura-coverage.xml $CI_PROJECT_DIR/
468-
- mkdir -p $CI_PROJECT_DIR/artifacts/lcov-report && cp -a /app/coverage/lcov-report $CI_PROJECT_DIR/artifacts/
469-
coverage: '/^All files[^|]*\|[^|]*\s+([\d\.]+)/'
470+
- cp /app/junit.xml $CI_PROJECT_DIR/junit-$CI_NODE_INDEX.xml
471+
- mkdir -p $CI_PROJECT_DIR/coverage-$CI_NODE_INDEX && cp -a /app/coverage-$CI_NODE_INDEX/. $CI_PROJECT_DIR/coverage-$CI_NODE_INDEX/
470472
artifacts:
471473
reports:
472-
coverage_report:
473-
coverage_format: cobertura
474-
path: cobertura-coverage.xml
475-
junit: junit.xml
474+
junit: junit-$CI_NODE_INDEX.xml
476475
paths:
477-
- artifacts/lcov-report
476+
- coverage-$CI_NODE_INDEX
478477
rules:
479478
- if: ($BUILD_WEB == "true") && ($DO_CHECKS == "true") && ($CI_COMMIT_BRANCH == $RELEASE_BRANCH)
480479
- if: ($BUILD_WEB == "true") && ($DO_CHECKS == "true") && ($CI_COMMIT_BRANCH != $RELEASE_BRANCH)
@@ -727,8 +726,49 @@ preview:backend:
727726
- app/proto/**/*
728727
- app/backend/**/*
729728

729+
preview:web-coverage:
730+
needs:
731+
- job: test:web
732+
artifacts: true
733+
- job: build:web-dev
734+
artifacts: false
735+
stage: preview
736+
image: $WEB_DEV_TAG
737+
inherit:
738+
# no docker login
739+
default: false
740+
script:
741+
- cd /app
742+
# Install nyc for merging coverage
743+
- npm install -g nyc
744+
# Merge coverage JSON files from all parallel workers
745+
- mkdir -p merged-coverage
746+
- nyc merge $CI_PROJECT_DIR/coverage-1 merged-coverage/coverage-1.json || true
747+
- nyc merge $CI_PROJECT_DIR/coverage-2 merged-coverage/coverage-2.json || true
748+
- nyc merge $CI_PROJECT_DIR/coverage-3 merged-coverage/coverage-3.json || true
749+
# Generate combined reports
750+
- nyc merge merged-coverage .nyc_output/coverage.json
751+
- nyc report --reporter=text --reporter=cobertura --reporter=lcov --report-dir=coverage
752+
# Move lcov-report to artifacts location
753+
- mkdir -p $CI_PROJECT_DIR/artifacts && mv coverage/lcov-report $CI_PROJECT_DIR/artifacts/
754+
- cp coverage/cobertura-coverage.xml $CI_PROJECT_DIR/
755+
coverage: '/^All files[^|]*\|[^|]*\s+([\d\.]+)/'
756+
artifacts:
757+
reports:
758+
coverage_report:
759+
coverage_format: cobertura
760+
path: cobertura-coverage.xml
761+
paths:
762+
- artifacts/lcov-report
763+
rules:
764+
- if: ($BUILD_WEB == "true") && ($DO_CHECKS == "true") && ($CI_COMMIT_BRANCH == $RELEASE_BRANCH)
765+
- if: ($BUILD_WEB == "true") && ($DO_CHECKS == "true") && ($CI_COMMIT_BRANCH != $RELEASE_BRANCH)
766+
changes:
767+
- app/proto/**/*
768+
- app/web/**/*
769+
730770
preview:wcov:
731-
needs: ["test:web"]
771+
needs: ["preview:web-coverage"]
732772
stage: preview
733773
image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest
734774
inherit:
@@ -884,6 +924,9 @@ wait:before-release:
884924
- job: test:web
885925
artifacts: false
886926
optional: true
927+
- job: preview:web-coverage
928+
artifacts: false
929+
optional: true
887930
- job: test:web-prettier
888931
artifacts: false
889932
optional: true
@@ -899,9 +942,6 @@ wait:before-release:
899942
- job: test:mobile-typecheck
900943
artifacts: false
901944
optional: true
902-
- job: test:mobile-expo-doctor
903-
artifacts: false
904-
optional: true
905945

906946
release:proxy:
907947
needs: ["wait:before-release"]
@@ -994,9 +1034,28 @@ release:nginx-next:
9941034
rules:
9951035
- if: $CI_COMMIT_BRANCH == $RELEASE_BRANCH
9961036

997-
release:deploy-info:
998-
needs: ["wait:before-release", "build:deploy-manifest"]
999-
stage: release
1037+
deploy:deploy-info:
1038+
needs:
1039+
- job: build:deploy-manifest
1040+
- job: release:proxy
1041+
artifacts: false
1042+
- job: release:nginx
1043+
artifacts: false
1044+
- job: release:prometheus
1045+
artifacts: false
1046+
- job: release:backend
1047+
artifacts: false
1048+
- job: release:media
1049+
artifacts: false
1050+
- job: release:web
1051+
artifacts: false
1052+
optional: true
1053+
- job: release:web-next
1054+
artifacts: false
1055+
optional: true
1056+
- job: release:nginx-next
1057+
artifacts: false
1058+
stage: deploy
10001059
image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest
10011060
inherit:
10021061
# no docker login

app/backend/Makefile

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Makefile for the backend of the application
22
# Run 'make [command]' in app/backend to execute the specified command
33

4-
UV_VERSION=0.9.21
4+
UV_VERSION=0.10.9
55
ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
66
PROTO_IMAGE=registry.gitlab.com/couchers/grpc
77

@@ -69,6 +69,25 @@ test:
6969
uv run pytest $(if $(file),src/tests/$(file),src/tests)
7070

7171

72+
# Run backend tests in Docker
73+
# Usage:
74+
# make docker-test → runs all tests
75+
# make docker-test file=test_file.py → runs tests in a specific file
76+
docker-test:
77+
$(eval COMPOSE_FILES := -f ../docker-compose.test.yml $(if $(filter Darwin,$(shell uname -s)),-f ../docker-compose.testmac.yml))
78+
docker compose $(COMPOSE_FILES) up -d --wait postgres_tests
79+
docker compose $(COMPOSE_FILES) run --rm --build \
80+
-v $(ROOT_DIR):/app \
81+
-v /app/.venv \
82+
-e DATABASE_CONNECTION_STRING=postgresql://postgres:06b3890acd2c235c41be0bbfe22f1b386a04bf02eedf8c977486355616be2aa1@postgres_tests:6544/testdb \
83+
--no-deps \
84+
backend_test_runner \
85+
pytest $(if $(file),src/tests/$(file),src/tests) --disable-warnings
86+
87+
teardown-docker-test:
88+
docker compose -f ../docker-compose.test.yml down
89+
90+
7291
run-deps:
7392
docker compose -f ../docker-compose.local-backend.yml up -d --build --wait
7493

app/backend/src/couchers/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,6 @@
111111
GALLERY_MAX_PHOTOS_VERIFIED = 4
112112

113113
COMPLETED_PROFILE_MINIMUM_CHAR_LENGTH = 150
114+
115+
# How long a container must run uninterrupted before /status reports stable=true
116+
STABLE_THRESHOLD_SECONDS = 15 * 60

app/backend/src/couchers/i18n/locales/de.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"event_not_found": "Event nicht gefunden.",
6969
"event_too_far_in_future": "Das Event muss innerhalb des nächsten Jahres beginnen.",
7070
"event_too_long": "Events dürfen nicht länger als 7 Tage dauern.",
71-
"event_transfer_permission_denied": "Du darfst dieses Ereignis nicht übertragen.",
71+
"event_transfer_permission_denied": "Du darfst dieses Event nicht übertragen.",
7272
"friend_request_not_found": "Diese Freundschaftsanfrage konnte nicht gefunden werden.",
7373
"friends_already_or_pending": "Du bist bereits mit diesem Nutzer befreundet oder hast ihm eine Freundschaftsanfrage gesendet.",
7474
"group_not_found": "Gruppe nicht gefunden.",
Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,24 @@
1-
{}
1+
{
2+
"errors": {
3+
"account_suspended": "Il tuo account è stato sospeso.",
4+
"admin_blog_title_too_long": "Il titolo del post è troppo lungo.",
5+
"already_admin": "Questo utente é già amministratore.",
6+
"already_have_dm": "Hai già uno scambio di messaggi con questo utente.",
7+
"already_in_community": "Sei già iscritto a quella comunità.",
8+
"already_in_group": "Sei già in quel gruppo.",
9+
"already_left_host_request_feedback": "Hai già lasciato una recensione per questa richiesta di ospitalità!",
10+
"at_least_two_users_required": "Devi specificare almeno 2 utenti",
11+
"bug_tool_request_failed": "Richiesta fallita",
12+
"cannot_create_discussion": "Non puoi creare una discussione in questo gruppo o comunità.",
13+
"cannot_edit_that_notification_preference": "Questa preferenza di notifica non può essere modificata dall'utente.",
14+
"cant_invite_self": "Non puoi invitare te stesso in una chat.",
15+
"cant_message_in_chat": "Non puoi inviare un messaggio in questa chat.",
16+
"cant_write_reference_for_request": "Non puoi scrivere una referenza per quella richiesta di ospitalità, oppure non é stata trovata.",
17+
"chat_initiation_rate_limit": "Hai inviato messaggi a parecchi utenti nelle ultime {{hours}} ore. Per evitare spam non puoi contattare altri utenti, per ora.",
18+
"country_required": "La Nazione é obbligatoria.",
19+
"date_from_after_one_year": "La data di partenza deve essere entro un anno da oggi.",
20+
"date_from_before_today": "La data di inizio deve essere oggi o più tardi.",
21+
"date_to_after_one_year": "Non puoi chiedere di essere ospitato per più di un anno.",
22+
"discussion_not_found": "Discussione non trovata."
23+
}
24+
}

app/backend/src/couchers/notifications/background.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,9 @@ def _send_push_notification(session: Session, user: User, notification: Notifica
123123

124124
def handle_notification(payload: jobs_pb2.HandleNotificationPayload) -> None:
125125
with session_scope() as session:
126+
# Select and lock the row.
126127
notification = session.execute(
127-
select(Notification).where(Notification.id == payload.notification_id)
128+
select(Notification).where(Notification.id == payload.notification_id).with_for_update()
128129
).scalar_one()
129130

130131
# Check moderation visibility if this notification is linked to moderated content
Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,88 @@
1-
{}
1+
{
2+
"topic_action_descriptions": {
3+
"host_request": {
4+
"missed_messages": "Et falten missatges en una sol·licitud d'amfitrió",
5+
"create": "Algú t'envia una sol·licitud d'allotjament",
6+
"accept": "Algú accepta la teva sol·licitud d'allotjament",
7+
"reject": "Algú rebutja la teva sol·licitud d'allotjament",
8+
"message": "Algú envia un missatge en una sol·licitud d'allotjament",
9+
"confirm": "Algú confirma la seva sol·licitud d'allotjament",
10+
"cancel": "Algú cancel·la la seva sol·licitud d'allotjament",
11+
"reminder": "No has respost a una sol·licitud d'allotjament pendent"
12+
},
13+
"chat": {
14+
"message": "Algú t'envia un missatge",
15+
"missed_messages": "Et perds missatges en un xat"
16+
},
17+
"general": {
18+
"new_blog_post": "S'ha publicat una nova entrada al blog"
19+
},
20+
"reference": {
21+
"receive_hosted": "Reps una referència d’algú que t’ha allotjat",
22+
"receive_friend": "Has rebut una referència d’un amic",
23+
"reminder_hosted": "Recordatori d’escriure una referència per a algú que vas allotjar",
24+
"reminder_surfed": "Recorda escriure una referència per a algú amb qui et vas allotjar",
25+
"receive_surfed": "Reps una referència d’algú a qui vas allotjar"
26+
},
27+
"friend_request": {
28+
"create": "Algú t'ha enviat una sol·licitud d'amistat",
29+
"accept": "Algú accepta la teva sol·licitud d'amistat"
30+
},
31+
"event": {
32+
"create_any": "Un usuari crea qualsevol esdeveniment a la teva comunitat (no revisat per un administrador)",
33+
"update": "S'ha actualitzat un esdeveniment al qual assisteixes",
34+
"cancel": "S'ha cancel·lat un esdeveniment al qual assisties",
35+
"invite_organizer": "Algú et convida a coorganitzar un esdeveniment",
36+
"comment": " Un usuari comenta un esdeveniment al qual assistiràs",
37+
"reminder": "Recordatori que un esdeveniment al qual assistiràs tindrà lloc aviat",
38+
"create_approved": "Un esdeveniment aprovat pels moderadors es crea a la teva comunitat",
39+
"delete": "S'ha eliminat un esdeveniment al qual assisties"
40+
},
41+
"onboarding": {
42+
"reminder": "Recorda completar el teu perfil després de registrar-te"
43+
},
44+
"badge": {
45+
"add": "S'ha afegit una insígnia al teu compte",
46+
"remove": "S'ha eliminat una insígnia del teu compte"
47+
},
48+
"donation": {
49+
"received": "La teva donació ha estat rebuda"
50+
},
51+
"password": {
52+
"change": "La teva contrasenya s'ha canviat"
53+
},
54+
"password_reset": {
55+
"start": "S'ha iniciat el restabliment de la contrasenya",
56+
"complete": "La contrasenya s'ha restablert correctament"
57+
},
58+
"account_deletion": {
59+
"recovered": "El teu compte ha estat recuperat (restaurat)",
60+
"complete": "El teu compte ha estat eliminat",
61+
"start": "Inicies l'eliminació del compte"
62+
},
63+
"api_key": {
64+
"create": "S'ha creat una clau d'API per al teu compte"
65+
},
66+
"phone_number": {
67+
"change": "El teu número de telèfon ha canviat",
68+
"verify": "El teu número de telèfon està verificat"
69+
},
70+
"birthdate": {
71+
"change": "La teva data de naixement ha estat canviada"
72+
},
73+
"discussion": {
74+
"create": "Algú crea una discussió en una comunitat de la qual formes part",
75+
"comment": "Algú comenta en una discussió que estàs seguint"
76+
},
77+
"thread": {
78+
"reply": "Algú respon al teu comentari"
79+
},
80+
"email_address": {
81+
"change": "S'ha iniciat el canvi de correu electrònic",
82+
"verify": "El teu nou correu electrònic està verificat"
83+
},
84+
"gender": {
85+
"change": "El gènere que es mostra al teu perfil s'ha canviat"
86+
}
87+
}
88+
}

app/backend/src/couchers/notifications/locales/cs.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,29 @@
5858
"donation__received": {
5959
"title": "Dar přijat"
6060
}
61+
},
62+
"topic_action_descriptions": {
63+
"host_request": {
64+
"cancel": "Někdo zruší žádost o ubytování",
65+
"reject": "Někdo odmítne tvou žádost o ubytování",
66+
"confirm": "Někdo potvrdí žádost o ubytování",
67+
"accept": "Někdo přijme tvou žádost o ubytování",
68+
"message": "Někdo ti pošle zprávu v žádosti o ubytování",
69+
"create": "Někdo ti zašle žádost o ubytování",
70+
"missed_messages": "Utekla ti zpráva v žádosti o ubytování"
71+
},
72+
"chat": {
73+
"missed_messages": "Utekly ti zprávy v chatu",
74+
"message": "Někdo ti pošle zprávu"
75+
},
76+
"general": {
77+
"new_blog_post": "Byl zveřejněn nový blogový příspěvek"
78+
},
79+
"phone_number": {
80+
"verify": "Tvé telefonní číslo je ověřeno."
81+
},
82+
"reference": {
83+
"receive_friend": "Přišla ti reference od přítele."
84+
}
6185
}
6286
}

0 commit comments

Comments
 (0)