Skip to content
3 changes: 2 additions & 1 deletion mergin/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ def list_projects(flag):
c = _init_client()
if c is None:
return
projects_list = c.projects_list(flag=flag)
resp = c.paginated_projects_list(flag=flag)
projects_list = resp["projects"]
for project in projects_list:
full_name = "{} / {}".format(project["namespace"], project["name"])
click.echo(" {:40}\t{:6.1f} MB\t{}".format(full_name, project["disk_usage"]/(1024*1024), project['version']))
Expand Down
55 changes: 54 additions & 1 deletion mergin/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ def create_project_and_push(self, project_name, directory, is_public=False):
if mp.inspect_files():
self.push_project(directory)

def projects_list(self, tags=None, user=None, flag=None, q=None):
def paginated_projects_list(self, page=1, per_page=50, tags=None, user=None, flag=None, name=None,
namespace=None, order_params=None):
"""
Find all available mergin projects.

Expand All @@ -300,6 +301,58 @@ def projects_list(self, tags=None, user=None, flag=None, q=None):
:param flag: Predefined filter flag ('created', 'shared')
:type flag: String

:param name: Filter projects with name like name
:type name: String

:param namespace: Filter projects with namespace like namespace
:type namespace: String

:param page: Page number for paginated projects list
:type page: Integer

:param per_page: Number of projects fetched per page, max 100 (restriction set by server)
:type per_page: Integer

:param order_params: optional attributes for sorting the list. It should be a comma separated attribute names
with _asc or _desc appended for sorting direction. For example: "namespace_asc,disk_usage_desc".
Available attrs: namespace, name, created, updated, disk_usage, creator
:type order_params: String

:rtype: List[Dict]
"""
params = {}
if tags:
params["tags"] = ",".join(tags)
if user:
params["user"] = user
if flag:
params["flag"] = flag
if name:
params["name"] = name
if namespace:
params["namespace"] = namespace
params["page"] = page
params["per_page"] = per_page
if order_params is not None:
params["order_params"] = order_params
resp = self.get("/v1/project/paginated", params)
projects = json.load(resp)
return projects

def projects_list(self, tags=None, user=None, flag=None, q=None):
"""
Find all available Mergin projects. It will always retrieve max 100 projects.
Consider using the paginated_projects_list instead.

:param tags: Filter projects by tags ('valid_qgis', 'mappin_use', input_use')
:type tags: List

:param user: Username for 'flag' filter. If not provided, it means user executing request.
:type user: String

:param flag: Predefined filter flag ('created', 'shared')
:type flag: String

:param q: Search query string
:type q: String

Expand Down
40 changes: 39 additions & 1 deletion mergin/test/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def toggle_geodiff(enabled):
def mc():
return create_client(API_USER, USER_PWD)


@pytest.fixture(scope='function')
def mc2():
return create_client(API_USER2, USER_PWD2)
Expand Down Expand Up @@ -64,8 +65,13 @@ def test_login(mc):


def test_create_delete_project(mc):
# create new (empty) project on server
test_project = 'test_create_delete'
project = API_USER + '/' + test_project
project_dir = os.path.join(TMP_DIR, test_project)
download_dir = os.path.join(TMP_DIR, 'download', test_project)

cleanup(mc, project, [project_dir, download_dir])
# create new (empty) project on server
mc.create_project(test_project)
projects = mc.projects_list(flag='created')
assert any(p for p in projects if p['name'] == test_project and p['namespace'] == API_USER)
Expand Down Expand Up @@ -698,3 +704,35 @@ def test_download_versions(mc):
# try to download not-existing version
with pytest.raises(ClientError):
mc.download_project(project, project_dir_v3, 'v3')


def test_paginated_project_list(mc):
"""Test the new endpoint for projects list with pagination, ordering etc."""
test_projects = dict()
for symb in "ABCDEF":
name = f"test_paginated_{symb}"
test_projects[name] = f"{API_USER}/{name}"

for name, full_name in test_projects.items():
cleanup(mc, full_name, [])
mc.create_project(name)

sorted_test_names = [n for n in sorted(test_projects.keys())]

resp = mc.paginated_projects_list(
flag='created', name="test_paginated", page=1, per_page=10, order_params="name_asc"
)
projects = resp["projects"]
count = resp["count"]
assert count == len(test_projects)
assert len(projects) == len(test_projects)
for i, project in enumerate(projects):
assert project["name"] == sorted_test_names[i]

resp = mc.paginated_projects_list(
flag='created', name="test_paginated", page=2, per_page=2, order_params="name_asc"
)
projects = resp["projects"]
assert len(projects) == 2
for i, project in enumerate(projects):
assert project["name"] == sorted_test_names[i+2]