From ae8addc8352740300769870a8c40b25b89d6080f Mon Sep 17 00:00:00 2001 From: Martin Varga Date: Fri, 7 Mar 2025 14:28:26 +0100 Subject: [PATCH 1/9] Do not add project creator to direct project members --- server/mergin/sync/models.py | 1 - server/mergin/tests/test_celery.py | 3 ++- .../mergin/tests/test_project_controller.py | 20 ++++++++++--------- server/mergin/tests/utils.py | 1 - 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/server/mergin/sync/models.py b/server/mergin/sync/models.py index 06a2d1e4..ba13b947 100644 --- a/server/mergin/sync/models.py +++ b/server/mergin/sync/models.py @@ -90,7 +90,6 @@ def __init__( self.public = kwargs.get("public", False) latest_files = LatestProjectFiles(project=self) db.session.add(latest_files) - self.set_role(creator.id, ProjectRole.OWNER) @property def storage(self): diff --git a/server/mergin/tests/test_celery.py b/server/mergin/tests/test_celery.py index e8346973..672ae60b 100644 --- a/server/mergin/tests/test_celery.py +++ b/server/mergin/tests/test_celery.py @@ -10,7 +10,7 @@ from ..app import db from ..config import Configuration -from ..sync.models import Project, AccessRequest, ProjectVersion +from ..sync.models import Project, AccessRequest, ProjectRole, ProjectVersion from ..celery import send_email_async from ..sync.tasks import remove_temp_files, remove_projects_backups from ..sync.storages.disk import move_to_tmp @@ -60,6 +60,7 @@ def test_send_email_from_flask(send_email_mock, client): user = User.query.filter(User.username == "mergin").first() test_workspace = create_workspace() p = create_project("testx", test_workspace, user) + p.set_role(user.id, ProjectRole.OWNER) user2 = add_user("test_user", "ilovemergin") login(client, "test_user", "ilovemergin") email_data = { diff --git a/server/mergin/tests/test_project_controller.py b/server/mergin/tests/test_project_controller.py index 9761ea05..0753d616 100644 --- a/server/mergin/tests/test_project_controller.py +++ b/server/mergin/tests/test_project_controller.py @@ -170,12 +170,13 @@ def test_get_paginated_projects(client): for i in range(14): create_project("foo" + str(i), test_workspace, user) - resp = client.get("/v1/project/paginated?page=1&per_page=10") + resp = client.get("/v1/project/paginated?page=1&per_page=10&order_params=created_asc") assert resp.status_code == 200 resp_data = json.loads(resp.data) assert len(resp_data.get("projects")) == 10 assert resp_data.get("count") == 15 - assert "foo7" in resp_data.get("projects")[9]["name"] + names = [p["name"] for p in resp_data.get("projects")] + assert "foo8" in resp_data.get("projects")[9]["name"] assert "v0" == resp_data.get("projects")[9]["version"] resp = client.get( @@ -194,11 +195,11 @@ def test_get_paginated_projects(client): # order by workspace name resp = client.get( - "/v1/project/paginated?page=2&per_page=10&order_params=workspace_asc" + "/v1/project/paginated?page=2&per_page=10&order_params=workspace_asc,created_asc" ) resp_data = json.loads(resp.data) assert len(resp_data.get("projects")) == 5 - assert "foo12" in resp_data.get("projects")[-1]["name"] + assert "foo13" in resp_data.get("projects")[-1]["name"] # tests backward compatibility sort resp_alt = client.get( "/v1/project/paginated?page=2&per_page=10&order_by=namespace&descending=false" @@ -295,15 +296,15 @@ def test_get_paginated_projects(client): Configuration.GLOBAL_READ = False Configuration.GLOBAL_WRITE = False Configuration.GLOBAL_ADMIN = False - # add new user and let him create one project (total 15+1) + # add new user and pretend he created one project (total 15+1) user2 = add_user("user2", "ilovemergin") - assert not test_workspace.user_has_permissions(user2, "read") create_project("created", test_workspace, user2) + # without implicit and explicit permissions user should not see any private project (even not that he 'created') + assert not test_workspace.user_has_permissions(user2, "read") login(client, "user2", "ilovemergin") # check one project is 'created', none is 'shared' resp = client.get("/v1/project/paginated?page=1&per_page=10&flag=created") - assert resp.json["count"] == 1 - assert resp.json["projects"][0]["name"] == "created" + assert resp.json["count"] == 0 resp = client.get("/v1/project/paginated?page=1&per_page=10&flag=shared") assert resp.json["count"] == 0 # share project explicitly @@ -2133,7 +2134,8 @@ def test_orphan_project(client): test_workspace = create_workspace() project = create_project("orphan", test_workspace, user) assert project.creator_id == user_id - assert project.get_role(user_id) is ProjectRole.OWNER + # creator is not direct member by default + assert not project.get_role(user_id) # user is removed by superuser login_as_admin(client) diff --git a/server/mergin/tests/utils.py b/server/mergin/tests/utils.py index 52fec093..0d4d4f9c 100644 --- a/server/mergin/tests/utils.py +++ b/server/mergin/tests/utils.py @@ -80,7 +80,6 @@ def create_project(name, workspace, user, **kwargs): p = Project(**project_params, **kwargs) p.updated = datetime.utcnow() - p.set_role(user.id, ProjectRole.OWNER) db.session.add(p) db.session.flush() changes = UploadChanges(added=[], updated=[], removed=[]) From 8917e49fbbc99b9975b3467f8674b7aee362d75b Mon Sep 17 00:00:00 2001 From: Martin Varga Date: Fri, 7 Mar 2025 14:31:03 +0100 Subject: [PATCH 2/9] black --- server/mergin/tests/test_project_controller.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/mergin/tests/test_project_controller.py b/server/mergin/tests/test_project_controller.py index 0753d616..652932f5 100644 --- a/server/mergin/tests/test_project_controller.py +++ b/server/mergin/tests/test_project_controller.py @@ -170,7 +170,9 @@ def test_get_paginated_projects(client): for i in range(14): create_project("foo" + str(i), test_workspace, user) - resp = client.get("/v1/project/paginated?page=1&per_page=10&order_params=created_asc") + resp = client.get( + "/v1/project/paginated?page=1&per_page=10&order_params=created_asc" + ) assert resp.status_code == 200 resp_data = json.loads(resp.data) assert len(resp_data.get("projects")) == 10 From 806cafe6a8513a951a96b780def444d05e39f0a7 Mon Sep 17 00:00:00 2001 From: Herman Snevajs Date: Mon, 10 Mar 2025 17:41:13 +0100 Subject: [PATCH 3/9] Dis/enable clone button based on selected workspace --- .../src/modules/project/components/CloneDialogTemplate.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web-app/packages/lib/src/modules/project/components/CloneDialogTemplate.vue b/web-app/packages/lib/src/modules/project/components/CloneDialogTemplate.vue index 491ec1c8..5d6fa39a 100644 --- a/web-app/packages/lib/src/modules/project/components/CloneDialogTemplate.vue +++ b/web-app/packages/lib/src/modules/project/components/CloneDialogTemplate.vue @@ -35,7 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial Date: Tue, 11 Mar 2025 10:16:27 +0100 Subject: [PATCH 4/9] Pass a prop from CE dialog --- .../lib/src/modules/project/components/CloneDialog.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web-app/packages/lib/src/modules/project/components/CloneDialog.vue b/web-app/packages/lib/src/modules/project/components/CloneDialog.vue index 4ee593dd..b525ed02 100644 --- a/web-app/packages/lib/src/modules/project/components/CloneDialog.vue +++ b/web-app/packages/lib/src/modules/project/components/CloneDialog.vue @@ -5,7 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial --> + diff --git a/web-app/packages/lib/src/common/components/types.ts b/web-app/packages/lib/src/common/components/types.ts index e8556642..245bc52f 100644 --- a/web-app/packages/lib/src/common/components/types.ts +++ b/web-app/packages/lib/src/common/components/types.ts @@ -15,3 +15,9 @@ export interface TableDataHeader { sortable?: boolean width?: number } + +export type TipMessageSeverity = 'info' | 'danger' + +export interface TipMessageProps { + severity?: TipMessageSeverity +} diff --git a/web-app/packages/lib/src/modules/dialog/components/ConfirmDialog.vue b/web-app/packages/lib/src/modules/dialog/components/ConfirmDialog.vue index 2fd35310..634cfb47 100644 --- a/web-app/packages/lib/src/modules/dialog/components/ConfirmDialog.vue +++ b/web-app/packages/lib/src/modules/dialog/components/ConfirmDialog.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial -->