Skip to content

Commit f0bc96d

Browse files
authored
Add paginated project list endpoint (#77)
1 parent 0fb4040 commit f0bc96d

File tree

3 files changed

+95
-3
lines changed

3 files changed

+95
-3
lines changed

mergin/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ def list_projects(flag):
137137
c = _init_client()
138138
if c is None:
139139
return
140-
projects_list = c.projects_list(flag=flag)
140+
resp = c.paginated_projects_list(flag=flag)
141+
projects_list = resp["projects"]
141142
for project in projects_list:
142143
full_name = "{} / {}".format(project["namespace"], project["name"])
143144
click.echo(" {:40}\t{:6.1f} MB\t{}".format(full_name, project["disk_usage"]/(1024*1024), project['version']))

mergin/client.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@ def create_project_and_push(self, project_name, directory, is_public=False):
287287
if mp.inspect_files():
288288
self.push_project(directory)
289289

290-
def projects_list(self, tags=None, user=None, flag=None, q=None):
290+
def paginated_projects_list(self, page=1, per_page=50, tags=None, user=None, flag=None, name=None,
291+
namespace=None, order_params=None):
291292
"""
292293
Find all available mergin projects.
293294
@@ -300,6 +301,58 @@ def projects_list(self, tags=None, user=None, flag=None, q=None):
300301
:param flag: Predefined filter flag ('created', 'shared')
301302
:type flag: String
302303
304+
:param name: Filter projects with name like name
305+
:type name: String
306+
307+
:param namespace: Filter projects with namespace like namespace
308+
:type namespace: String
309+
310+
:param page: Page number for paginated projects list
311+
:type page: Integer
312+
313+
:param per_page: Number of projects fetched per page, max 100 (restriction set by server)
314+
:type per_page: Integer
315+
316+
:param order_params: optional attributes for sorting the list. It should be a comma separated attribute names
317+
with _asc or _desc appended for sorting direction. For example: "namespace_asc,disk_usage_desc".
318+
Available attrs: namespace, name, created, updated, disk_usage, creator
319+
:type order_params: String
320+
321+
:rtype: List[Dict]
322+
"""
323+
params = {}
324+
if tags:
325+
params["tags"] = ",".join(tags)
326+
if user:
327+
params["user"] = user
328+
if flag:
329+
params["flag"] = flag
330+
if name:
331+
params["name"] = name
332+
if namespace:
333+
params["namespace"] = namespace
334+
params["page"] = page
335+
params["per_page"] = per_page
336+
if order_params is not None:
337+
params["order_params"] = order_params
338+
resp = self.get("/v1/project/paginated", params)
339+
projects = json.load(resp)
340+
return projects
341+
342+
def projects_list(self, tags=None, user=None, flag=None, q=None):
343+
"""
344+
Find all available Mergin projects. It will always retrieve max 100 projects.
345+
Consider using the paginated_projects_list instead.
346+
347+
:param tags: Filter projects by tags ('valid_qgis', 'mappin_use', input_use')
348+
:type tags: List
349+
350+
:param user: Username for 'flag' filter. If not provided, it means user executing request.
351+
:type user: String
352+
353+
:param flag: Predefined filter flag ('created', 'shared')
354+
:type flag: String
355+
303356
:param q: Search query string
304357
:type q: String
305358

mergin/test/test_client.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def toggle_geodiff(enabled):
2626
def mc():
2727
return create_client(API_USER, USER_PWD)
2828

29+
2930
@pytest.fixture(scope='function')
3031
def mc2():
3132
return create_client(API_USER2, USER_PWD2)
@@ -64,8 +65,13 @@ def test_login(mc):
6465

6566

6667
def test_create_delete_project(mc):
67-
# create new (empty) project on server
6868
test_project = 'test_create_delete'
69+
project = API_USER + '/' + test_project
70+
project_dir = os.path.join(TMP_DIR, test_project)
71+
download_dir = os.path.join(TMP_DIR, 'download', test_project)
72+
73+
cleanup(mc, project, [project_dir, download_dir])
74+
# create new (empty) project on server
6975
mc.create_project(test_project)
7076
projects = mc.projects_list(flag='created')
7177
assert any(p for p in projects if p['name'] == test_project and p['namespace'] == API_USER)
@@ -698,3 +704,35 @@ def test_download_versions(mc):
698704
# try to download not-existing version
699705
with pytest.raises(ClientError):
700706
mc.download_project(project, project_dir_v3, 'v3')
707+
708+
709+
def test_paginated_project_list(mc):
710+
"""Test the new endpoint for projects list with pagination, ordering etc."""
711+
test_projects = dict()
712+
for symb in "ABCDEF":
713+
name = f"test_paginated_{symb}"
714+
test_projects[name] = f"{API_USER}/{name}"
715+
716+
for name, full_name in test_projects.items():
717+
cleanup(mc, full_name, [])
718+
mc.create_project(name)
719+
720+
sorted_test_names = [n for n in sorted(test_projects.keys())]
721+
722+
resp = mc.paginated_projects_list(
723+
flag='created', name="test_paginated", page=1, per_page=10, order_params="name_asc"
724+
)
725+
projects = resp["projects"]
726+
count = resp["count"]
727+
assert count == len(test_projects)
728+
assert len(projects) == len(test_projects)
729+
for i, project in enumerate(projects):
730+
assert project["name"] == sorted_test_names[i]
731+
732+
resp = mc.paginated_projects_list(
733+
flag='created', name="test_paginated", page=2, per_page=2, order_params="name_asc"
734+
)
735+
projects = resp["projects"]
736+
assert len(projects) == 2
737+
for i, project in enumerate(projects):
738+
assert project["name"] == sorted_test_names[i+2]

0 commit comments

Comments
 (0)