diff --git a/LICENSES/CLA-signed-list.md b/LICENSES/CLA-signed-list.md index 627b7e57..bd7ccdfe 100644 --- a/LICENSES/CLA-signed-list.md +++ b/LICENSES/CLA-signed-list.md @@ -4,6 +4,7 @@ A/ You have read and agree to the individual CLA: https://merginmaps.com/license * `alhirzel`, 20th December 2023 * `uprel`, 18th March 2024 +* `enockseth`, 5th May 2025 B/ I have read and agree with entity CLA for my company: https://merginmaps.com/licenses/entity-cla diff --git a/deployment/community/docker-compose.debug.yml b/deployment/community/docker-compose.debug.yml new file mode 100644 index 00000000..09a88a6b --- /dev/null +++ b/deployment/community/docker-compose.debug.yml @@ -0,0 +1,51 @@ + + +services: + server: + image: server + build: + context: ../../server + dockerfile: Dockerfile + env_file: + - .prod.env + - .dev.env + environment: + - FLASK_ENV=development + - FLASK_DEBUG=1 + - GEVENT_SUPPORT=1 + command: ["pip install debugpy -t /tmp && python3 /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 -m flask run -h 0.0.0.0 -p 5000"] + ports: + - 5000:5000 + - 5678:5678 + volumes: + - ../../server/:/app + celery-beat: + image: celery-beat + build: + context: ../../server + dockerfile: Dockerfile + env_file: + - .prod.env + - .dev.env + celery-worker: + image: celery-worker + build: + context: ../../server + dockerfile: Dockerfile + env_file: + - .prod.env + - .dev.env + web: + image: merginmaps-frontend + build: + context: ../../web-app + dockerfile: Dockerfile + maildev: + image: maildev/maildev + container_name: merginmaps-maildev + restart: always + ports: + - 1080:1080 + - 1025:1025 + networks: + - merginmaps diff --git a/development.md b/development.md index 42ad83d3..b2a1be08 100644 --- a/development.md +++ b/development.md @@ -72,6 +72,7 @@ cd deployment/community/ cp .env.template .prod.env # Run the docker composition with the current Dockerfiles +cp .env.template .prod.env docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d # Give ownership of the ./projects folder to user that is running the gunicorn container @@ -96,6 +97,14 @@ docker exec -it merginmaps-server flask server send-check-email --email admin@e In docker-compose.dev.yml is started maildev/maildev image that can be used to test emails (see [https://github.com/maildev/maildev/](https://github.com/maildev/maildev/)). In localhost:1080 you can see the emails sent by the application in web interface. +### Running with remote debugger +If you want to run the application with remote debugger, you can use debug compose file with attatched source code and reload. +It starts a debugpy session on port 5678 you can attach to. + +```shell +docker compose -f docker-compose.yml -f docker-compose.debug.yml up +``` + ## Running tests To launch the unit tests run: ```shell diff --git a/server/mergin/sync/private_api_controller.py b/server/mergin/sync/private_api_controller.py index 44018c02..aaa77216 100644 --- a/server/mergin/sync/private_api_controller.py +++ b/server/mergin/sync/private_api_controller.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial import os from datetime import datetime, timedelta, timezone +from urllib.parse import quote from blinker import signal from connexion import NoContent from flask import ( @@ -347,8 +348,9 @@ def download_project(id: str, version=None): # noqa: E501 # pylint: disable=W06 else: resp = send_file(project_version.zip_path, mimetype="application/zip") + file_name = quote(f"{project.name}-v{lookup_version}.zip".encode("utf-8")) resp.headers["Content-Disposition"] = ( - f"attachment; filename={project.name}-v{lookup_version}.zip" + f"attachment; filename*=UTF-8''{file_name}" ) return resp diff --git a/web-app/packages/lib/src/modules/project/store.ts b/web-app/packages/lib/src/modules/project/store.ts index 5cf79fb2..182bdea2 100644 --- a/web-app/packages/lib/src/modules/project/store.ts +++ b/web-app/packages/lib/src/modules/project/store.ts @@ -708,11 +708,9 @@ export const useProjectStore = defineStore('projectModule', { async downloadArchive(payload: DownloadPayload) { const notificationStore = useNotificationStore() - this.cancelDownloadArchive() + await this.cancelDownloadArchive() + this.projectDownloadingVersion = payload.versionId this.projectDownloading = true - if (payload.versionId) { - this.projectDownloadingVersion = payload.versionId - } const errorMessage = 'Failed to download project archive. Please try again later.' @@ -728,7 +726,7 @@ export const useProjectStore = defineStore('projectModule', { text: exceedMessage, life: 6000 }) - this.cancelDownloadArchive() + await this.cancelDownloadArchive() return } @@ -765,7 +763,7 @@ export const useProjectStore = defineStore('projectModule', { pollDownloadArchive() }, - cancelDownloadArchive() { + async cancelDownloadArchive() { if (downloadArchiveTimeout) { clearTimeout(downloadArchiveTimeout) downloadArchiveTimeout = null