Skip to content

Commit c846724

Browse files
authored
Merge pull request #251 from MerginMaps/create_invitation_method
Create invitation method
2 parents b912616 + fd95eb7 commit c846724

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

mergin/client.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,14 @@ def has_editor_support(self):
12781278
"""
12791279
return is_version_acceptable(self.server_version(), "2024.4.0")
12801280

1281+
def check_collaborators_members_support(self):
1282+
"""
1283+
Check if the server is compatible with v2 endpoints for project collaborators and workspace members
1284+
"""
1285+
min_version = "2025.1.0"
1286+
if not is_version_acceptable(self.server_version(), f"{min_version}"):
1287+
raise NotImplementedError(f"This needs server at version {min_version} or later")
1288+
12811289
def create_user(
12821290
self,
12831291
email: str,
@@ -1297,6 +1305,7 @@ def create_user(
12971305
param username: username - will be autogenerated from the email if not provided
12981306
param notify_user: flag for email notifications - confirmation email will be sent
12991307
"""
1308+
self.check_collaborators_members_support()
13001309
params = {
13011310
"email": email,
13021311
"password": password,
@@ -1313,13 +1322,15 @@ def get_workspace_member(self, workspace_id: int, user_id: int) -> dict:
13131322
"""
13141323
Get a workspace member detail
13151324
"""
1325+
self.check_collaborators_members_support()
13161326
resp = self.get(f"v2/workspaces/{workspace_id}/members/{user_id}")
13171327
return json.load(resp)
13181328

13191329
def list_workspace_members(self, workspace_id: int) -> List[dict]:
13201330
"""
13211331
Get a list of workspace members
13221332
"""
1333+
self.check_collaborators_members_support()
13231334
resp = self.get(f"v2/workspaces/{workspace_id}/members")
13241335
return json.load(resp)
13251336

@@ -1331,6 +1342,7 @@ def update_workspace_member(
13311342
13321343
param reset_projects_roles: all project specific roles will be removed
13331344
"""
1345+
self.check_collaborators_members_support()
13341346
params = {
13351347
"reset_projects_roles": reset_projects_roles,
13361348
"workspace_role": workspace_role.value,
@@ -1342,12 +1354,14 @@ def remove_workspace_member(self, workspace_id: int, user_id: int):
13421354
"""
13431355
Remove a user from workspace members
13441356
"""
1357+
self.check_collaborators_members_support()
13451358
self.delete(f"v2/workspaces/{workspace_id}/members/{user_id}")
13461359

13471360
def list_project_collaborators(self, project_id: str) -> List[dict]:
13481361
"""
13491362
Get a list of project collaborators
13501363
"""
1364+
self.check_collaborators_members_support()
13511365
project_collaborators = self.get(f"v2/projects/{project_id}/collaborators")
13521366
return json.load(project_collaborators)
13531367

@@ -1358,6 +1372,7 @@ def add_project_collaborator(self, project_id: str, user: str, project_role: Pro
13581372
13591373
param user: login (username or email) of the user
13601374
"""
1375+
self.check_collaborators_members_support()
13611376
params = {"role": project_role.value, "user": user}
13621377
project_collaborator = self.post(f"v2/projects/{project_id}/collaborators", params, json_headers)
13631378
return json.load(project_collaborator)
@@ -1367,6 +1382,7 @@ def update_project_collaborator(self, project_id: str, user_id: int, project_rol
13671382
Update project role of the existing project collaborator.
13681383
Fails if user is not a member of the project yet.
13691384
"""
1385+
self.check_collaborators_members_support()
13701386
params = {"role": project_role.value}
13711387
project_collaborator = self.patch(f"v2/projects/{project_id}/collaborators/{user_id}", params, json_headers)
13721388
return json.load(project_collaborator)
@@ -1375,6 +1391,7 @@ def remove_project_collaborator(self, project_id: str, user_id: int):
13751391
"""
13761392
Remove a user from project collaborators
13771393
"""
1394+
self.check_collaborators_members_support()
13781395
self.delete(f"v2/projects/{project_id}/collaborators/{user_id}")
13791396

13801397
def server_config(self) -> dict:
@@ -1441,3 +1458,14 @@ def send_logs(
14411458
else:
14421459
request = urllib.request.Request(url, data=payload, headers=header)
14431460
return self._do_request(request)
1461+
1462+
def create_invitation(self, workspace_id: int, email: str, workspace_role: WorkspaceRole):
1463+
"""
1464+
Create invitation to workspace for specific role
1465+
"""
1466+
min_version = "2025.6.1"
1467+
if not is_version_acceptable(self.server_version(), min_version):
1468+
raise NotImplementedError(f"This needs server at version {min_version} or later")
1469+
params = {"email": email, "role": workspace_role.value}
1470+
ws_inv = self.post(f"v2/workspaces/{workspace_id}/invitations", params, json_headers)
1471+
return json.load(ws_inv)

mergin/test/test_client.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
decode_token_data,
2222
TokenError,
2323
ServerType,
24-
WorkspaceRole,
2524
)
2625
from ..client_push import push_project_async, push_project_cancel
2726
from ..client_pull import (
@@ -2913,6 +2912,22 @@ def test_do_request_error_handling(mc: MerginClient):
29132912
assert "Passwords must be at least 8 characters long." in e.value.detail
29142913

29152914

2915+
def test_create_invitation(mc: MerginClient):
2916+
"""Test client method to create workspace invitation"""
2917+
workspace_id = next((w["id"] for w in mc.workspaces_list() if w["name"] == mc.username()))
2918+
role = WorkspaceRole.WRITER
2919+
email = "invitation@client.py"
2920+
inv = mc.create_invitation(workspace_id, email, role)
2921+
assert inv["email"] == email
2922+
assert inv["role"] == role.value
2923+
mc.delete(f"v1/workspace/invitation/{inv['id']}") # resolves invitation to allow another invitation to the email
2924+
role = WorkspaceRole.GUEST
2925+
inv = mc.create_invitation(workspace_id, email, role)
2926+
assert inv["email"] == email
2927+
assert "projects" not in inv
2928+
mc.delete(f"v1/workspace/invitation/{inv['id']}")
2929+
2930+
29162931
def test_validate_auth(mc: MerginClient):
29172932
"""Test validate authentication under different scenarios."""
29182933

0 commit comments

Comments
 (0)