Skip to content

Commit 0f45468

Browse files
authored
Workspaces (#150)
* add workspaces endpoint * Add global_namespace() and server_type() methods * black * cache global namespace while checking server type * black * Add only_namespace parameter to projects_list * switch to using /v1/user/profile for new servers * remove unused method global_namespace * use enum for ServerType and remove unused var * rename global_namespace to global_workspace, fix blunder * use new api for server_type and workspace services
1 parent 499d531 commit 0f45468

File tree

1 file changed

+91
-4
lines changed

1 file changed

+91
-4
lines changed

mergin/client.py

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from datetime import datetime, timezone
1313
import dateutil.parser
1414
import ssl
15+
from enum import Enum, auto
1516
import re
1617

1718
from .common import ClientError, LoginError, InvalidProject
@@ -37,6 +38,13 @@ class TokenError(Exception):
3738
pass
3839

3940

41+
class ServerType(Enum):
42+
OLD = auto() # Server is old and does not support workspaces
43+
CE = auto() # Server is Community Edition
44+
EE = auto() # Server is Enterprise Edition
45+
SAAS = auto() # Server is SaaS
46+
47+
4048
def decode_token_data(token):
4149
token_prefix = "Bearer ."
4250
if not token.startswith(token_prefix):
@@ -70,6 +78,7 @@ def __init__(self, url=None, auth_token=None, login=None, password=None, plugin_
7078
self._auth_params = None
7179
self._auth_session = None
7280
self._user_info = None
81+
self._server_type = None
7382
self.client_version = "Python-client/" + __version__
7483
if plugin_version is not None: # this could be e.g. "Plugin/2020.1 QGIS/3.14"
7584
self.client_version += " " + plugin_version
@@ -310,6 +319,7 @@ def user_service(self):
310319
Requests information about user from /user/service endpoint if such exists in self.url server.
311320
312321
Returns response from server as JSON dict or None if endpoint is not found
322+
This can be removed once our SaaS server is upgraded to support workspaces
313323
"""
314324

315325
try:
@@ -322,6 +332,58 @@ def user_service(self):
322332

323333
return response
324334

335+
def workspace_service(self, workspace_id):
336+
"""
337+
This Requests information about a workspace service from /workspace/{id}/service endpoint,
338+
if such exists in self.url server.
339+
340+
Returns response from server as JSON dict or None if endpoint is not found
341+
"""
342+
343+
try:
344+
response = self.get(f"/v1/workspace/{workspace_id}/service")
345+
except ClientError as e:
346+
self.log.debug(f"Unable to query for /workspace/{workspace_id}/service endpoint")
347+
return
348+
349+
response = json.loads(response.read())
350+
351+
return response
352+
353+
def server_type(self):
354+
"""
355+
Returns the deployment type of the server
356+
357+
The value is cached for self's lifetime
358+
359+
:returns: ServerType of server deployment
360+
:rtype: ServerType
361+
"""
362+
if not self._server_type:
363+
try:
364+
resp = self.get("/config")
365+
config = json.load(resp)
366+
if config["server_type"] == "ce":
367+
self._server_type = ServerType.CE
368+
elif config["server_type"] == "ee":
369+
self._server_type = ServerType.EE
370+
elif config["server_type"] == "saas":
371+
self._server_type = ServerType.SAAS
372+
except (ClientError, KeyError):
373+
self._server_type = ServerType.OLD
374+
375+
return self._server_type
376+
377+
def workspaces_list(self):
378+
"""
379+
Find all available workspaces
380+
381+
:rtype: List[Dict]
382+
"""
383+
resp = self.get("/v1/workspaces")
384+
workspaces = json.load(resp)
385+
return workspaces
386+
325387
def create_project(self, project_name, is_public=False, namespace=None):
326388
"""
327389
Create new project repository in user namespace on Mergin Maps server.
@@ -367,7 +429,16 @@ def create_project_and_push(self, project_name, directory, is_public=False, name
367429
self.push_project(directory)
368430

369431
def paginated_projects_list(
370-
self, page=1, per_page=50, tags=None, user=None, flag=None, name=None, namespace=None, order_params=None
432+
self,
433+
page=1,
434+
per_page=50,
435+
tags=None,
436+
user=None,
437+
flag=None,
438+
name=None,
439+
only_namespace=None,
440+
namespace=None,
441+
order_params=None,
371442
):
372443
"""
373444
Find all available Mergin Maps projects.
@@ -384,6 +455,9 @@ def paginated_projects_list(
384455
:param name: Filter projects with name like name
385456
:type name: String
386457
458+
:param only_namespace: Filter projects with namespace exactly equal to namespace
459+
:type namespace: String
460+
387461
:param namespace: Filter projects with namespace like namespace
388462
:type namespace: String
389463
@@ -409,7 +483,9 @@ def paginated_projects_list(
409483
params["flag"] = flag
410484
if name:
411485
params["name"] = name
412-
if namespace:
486+
if only_namespace:
487+
params["only_namespace"] = only_namespace
488+
elif namespace:
413489
params["namespace"] = namespace
414490
params["page"] = page
415491
params["per_page"] = per_page
@@ -419,7 +495,9 @@ def paginated_projects_list(
419495
projects = json.load(resp)
420496
return projects
421497

422-
def projects_list(self, tags=None, user=None, flag=None, name=None, namespace=None, order_params=None):
498+
def projects_list(
499+
self, tags=None, user=None, flag=None, name=None, only_namespace=None, namespace=None, order_params=None
500+
):
423501
"""
424502
Find all available Mergin Maps projects.
425503
@@ -437,6 +515,9 @@ def projects_list(self, tags=None, user=None, flag=None, name=None, namespace=No
437515
:param name: Filter projects with name like name
438516
:type name: String
439517
518+
:param only_namespace: Filter projects with namespace exactly equal to namespace
519+
:type namespace: String
520+
440521
:param namespace: Filter projects with namespace like namespace
441522
:type namespace: String
442523
@@ -458,6 +539,7 @@ def projects_list(self, tags=None, user=None, flag=None, name=None, namespace=No
458539
user=user,
459540
flag=flag,
460541
name=name,
542+
only_namespace=only_namespace,
461543
namespace=namespace,
462544
order_params=order_params,
463545
)
@@ -558,7 +640,11 @@ def enough_storage_available(self, data):
558640
return True, free_space
559641

560642
def user_info(self):
561-
resp = self.get("/v1/user/" + self.username())
643+
server_type = self.server_type()
644+
if server_type == ServerType.OLD:
645+
resp = self.get("/v1/user/" + self.username())
646+
else:
647+
resp = self.get("/v1/user/profile")
562648
return json.load(resp)
563649

564650
def set_project_access(self, project_path, access):
@@ -709,6 +795,7 @@ def project_status(self, directory):
709795
project_path = mp.metadata["name"]
710796
local_version = mp.metadata["version"]
711797
server_info = self.project_info(project_path, since=local_version)
798+
712799
pull_changes = mp.get_pull_changes(server_info["files"])
713800

714801
push_changes = mp.get_push_changes()

0 commit comments

Comments
 (0)