12
12
from datetime import datetime , timezone
13
13
import dateutil .parser
14
14
import ssl
15
+ from enum import Enum , auto
15
16
import re
16
17
17
18
from .common import ClientError , LoginError , InvalidProject
@@ -37,6 +38,13 @@ class TokenError(Exception):
37
38
pass
38
39
39
40
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
+
40
48
def decode_token_data (token ):
41
49
token_prefix = "Bearer ."
42
50
if not token .startswith (token_prefix ):
@@ -70,6 +78,7 @@ def __init__(self, url=None, auth_token=None, login=None, password=None, plugin_
70
78
self ._auth_params = None
71
79
self ._auth_session = None
72
80
self ._user_info = None
81
+ self ._server_type = None
73
82
self .client_version = "Python-client/" + __version__
74
83
if plugin_version is not None : # this could be e.g. "Plugin/2020.1 QGIS/3.14"
75
84
self .client_version += " " + plugin_version
@@ -310,6 +319,7 @@ def user_service(self):
310
319
Requests information about user from /user/service endpoint if such exists in self.url server.
311
320
312
321
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
313
323
"""
314
324
315
325
try :
@@ -322,6 +332,58 @@ def user_service(self):
322
332
323
333
return response
324
334
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
+
325
387
def create_project (self , project_name , is_public = False , namespace = None ):
326
388
"""
327
389
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
367
429
self .push_project (directory )
368
430
369
431
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 ,
371
442
):
372
443
"""
373
444
Find all available Mergin Maps projects.
@@ -384,6 +455,9 @@ def paginated_projects_list(
384
455
:param name: Filter projects with name like name
385
456
:type name: String
386
457
458
+ :param only_namespace: Filter projects with namespace exactly equal to namespace
459
+ :type namespace: String
460
+
387
461
:param namespace: Filter projects with namespace like namespace
388
462
:type namespace: String
389
463
@@ -409,7 +483,9 @@ def paginated_projects_list(
409
483
params ["flag" ] = flag
410
484
if name :
411
485
params ["name" ] = name
412
- if namespace :
486
+ if only_namespace :
487
+ params ["only_namespace" ] = only_namespace
488
+ elif namespace :
413
489
params ["namespace" ] = namespace
414
490
params ["page" ] = page
415
491
params ["per_page" ] = per_page
@@ -419,7 +495,9 @@ def paginated_projects_list(
419
495
projects = json .load (resp )
420
496
return projects
421
497
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
+ ):
423
501
"""
424
502
Find all available Mergin Maps projects.
425
503
@@ -437,6 +515,9 @@ def projects_list(self, tags=None, user=None, flag=None, name=None, namespace=No
437
515
:param name: Filter projects with name like name
438
516
:type name: String
439
517
518
+ :param only_namespace: Filter projects with namespace exactly equal to namespace
519
+ :type namespace: String
520
+
440
521
:param namespace: Filter projects with namespace like namespace
441
522
:type namespace: String
442
523
@@ -458,6 +539,7 @@ def projects_list(self, tags=None, user=None, flag=None, name=None, namespace=No
458
539
user = user ,
459
540
flag = flag ,
460
541
name = name ,
542
+ only_namespace = only_namespace ,
461
543
namespace = namespace ,
462
544
order_params = order_params ,
463
545
)
@@ -558,7 +640,11 @@ def enough_storage_available(self, data):
558
640
return True , free_space
559
641
560
642
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" )
562
648
return json .load (resp )
563
649
564
650
def set_project_access (self , project_path , access ):
@@ -709,6 +795,7 @@ def project_status(self, directory):
709
795
project_path = mp .metadata ["name" ]
710
796
local_version = mp .metadata ["version" ]
711
797
server_info = self .project_info (project_path , since = local_version )
798
+
712
799
pull_changes = mp .get_pull_changes (server_info ["files" ])
713
800
714
801
push_changes = mp .get_push_changes ()
0 commit comments