Skip to content

Commit 6c5f53c

Browse files
authored
Merge pull request #64 from opengisch/patch_project
Add endpoint to patch the project and pretty print project data
2 parents 02cb0bf + 9b6bb22 commit 6c5f53c

3 files changed

Lines changed: 134 additions & 8 deletions

File tree

qfieldcloud_sdk/cli.py

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import click
77

88
from . import sdk
9-
from .utils import log, print_json
9+
from .utils import format_project_table, log, print_json
1010

1111
QFIELDCLOUD_DEFAULT_URL = "https://app.qfield.cloud/api/v1/"
1212

@@ -200,9 +200,8 @@ def list_projects(ctx: Context, include_public: bool, **opts) -> None:
200200
print_json(projects)
201201
else:
202202
if projects:
203-
log("Projects:")
204-
for project in projects:
205-
log(f'{project["id"]}\t{project["owner"]}/{project["name"]}')
203+
log("Projects the current user has access to:")
204+
log(format_project_table(projects))
206205
else:
207206
log("User does not have any projects yet.")
208207

@@ -258,9 +257,8 @@ def create_project(ctx: Context, name, owner, description, is_public):
258257
if ctx.obj["format_json"]:
259258
print_json(project)
260259
else:
261-
log(
262-
f'Created project "{project["owner"]}/{project["name"]}" with project id "{project["id"]}".'
263-
)
260+
log("Created project:")
261+
log(format_project_table([project]))
264262

265263

266264
@cli.command()
@@ -371,6 +369,47 @@ def download_files(
371369
log(f"No files to download for project {project_id}")
372370

373371

372+
@cli.command()
373+
@click.argument("project_id")
374+
@click.option(
375+
"--name",
376+
help="New project name",
377+
)
378+
@click.option(
379+
"--description",
380+
help="New project description",
381+
)
382+
@click.option(
383+
"--owner",
384+
help="Transfer the project to a new owner",
385+
)
386+
@click.option(
387+
"--is-public/--is-no-public",
388+
is_flag=True,
389+
help="Whether the project shall be public",
390+
)
391+
@click.pass_context
392+
def patch_project(
393+
ctx: Context,
394+
project_id: str,
395+
name: Optional[str] = None,
396+
description: Optional[str] = None,
397+
owner: Optional[str] = None,
398+
is_public: Optional[bool] = None,
399+
) -> None:
400+
"""Patch the project with new data. Pass only the parameters that shall be changed."""
401+
402+
project = ctx.obj["client"].patch_project(
403+
project_id, name=name, owner=owner, description=description, is_public=is_public
404+
)
405+
406+
if ctx.obj["format_json"]:
407+
print_json(project)
408+
else:
409+
log("Patched project:")
410+
log(format_project_table([project]))
411+
412+
374413
@cli.command()
375414
@click.argument("project_id")
376415
@click.argument("paths", nargs=-1, required=True)

qfieldcloud_sdk/sdk.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,48 @@ def delete_project(self, project_id: str) -> requests.Response:
416416

417417
return resp
418418

419+
def patch_project(
420+
self,
421+
project_id: str,
422+
name: Optional[str] = None,
423+
owner: Optional[str] = None,
424+
description: Optional[str] = None,
425+
is_public: Optional[bool] = None,
426+
) -> Dict[str, Any]:
427+
"""Update a project.
428+
429+
Args:
430+
project_id (str): Project ID.
431+
name (str | None): if passed, the new name. Defaults to None.
432+
owner (str | None, optional): if passed, the new owner. Defaults to None.
433+
description (str, optional): if passed, the new description. Defaults to None.
434+
is_public (bool, optional): if passed, the new public setting. Defaults to None.
435+
436+
Returns:
437+
Dict[str, Any]: the updated project
438+
"""
439+
project_data: dict[str, Any] = {}
440+
441+
if name:
442+
project_data["name"] = name
443+
444+
if description:
445+
project_data["description"] = description
446+
447+
if owner:
448+
project_data["owner"] = owner
449+
450+
if is_public:
451+
project_data["is_public"] = is_public
452+
453+
resp = self._request(
454+
"PATCH",
455+
f"projects/{project_id}",
456+
project_data,
457+
)
458+
459+
return resp.json()
460+
419461
def upload_files(
420462
self,
421463
project_id: str,
@@ -1068,7 +1110,7 @@ def download_file(
10681110
progress_bar = tqdm(
10691111
total=content_length,
10701112
unit_scale=True,
1071-
desc=remote_filename,
1113+
desc=str(remote_filename),
10721114
)
10731115
download_file = CallbackIOWrapper(progress_bar.update, f, "write")
10741116
else:

qfieldcloud_sdk/utils.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33
import os
44
import sys
5+
from typing import List
56

67

78
def print_json(data):
@@ -69,3 +70,47 @@ def calc_etag(filename: str, part_size: int = 8 * 1024 * 1024) -> str:
6970
final_md5sum = hashlib.md5(b"".join(md5sums))
7071

7172
return "{}-{}".format(final_md5sum.hexdigest(), len(md5sums))
73+
74+
75+
def format_table(headers: List[str], data: List[List]) -> str:
76+
length_by_column: List[int] = []
77+
78+
for col in headers:
79+
length_by_column.append(len(col))
80+
81+
for row in data:
82+
for idx, col in enumerate(row):
83+
length_by_column[idx] = max(length_by_column[idx], len(str(col)))
84+
85+
row_tmpl = "|"
86+
for col_length in length_by_column:
87+
row_tmpl += " {:<" + str(col_length) + "} |"
88+
89+
result = row_tmpl.format(*headers)
90+
result += "\r\n"
91+
result += "-" * (sum(length_by_column) + len(headers) * 3 + 1)
92+
93+
for row in data:
94+
result += "\r\n"
95+
result += row_tmpl.format(*row)
96+
97+
return result
98+
99+
100+
def format_project_table(projects: List) -> str:
101+
data = []
102+
103+
for project in projects:
104+
data.append(
105+
[
106+
project["id"],
107+
project["owner"] + "/" + project["name"],
108+
project["is_public"],
109+
project["description"],
110+
]
111+
)
112+
113+
return format_table(
114+
headers=["ID", "OWNER/NAME", "IS PUBLIC", "DESCRIPTION"],
115+
data=data,
116+
)

0 commit comments

Comments
 (0)