Skip to content

Project history : Add functionnalities for the version viewerin the QGIS plugin #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 67 additions & 13 deletions mergin/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,17 @@ def workspace_service(self, workspace_id):

return response

def workspace_usage(self, workspace_id):
"""
This Requests information about a workspace usage from /workspace/{id}/usage endpoint,
if such exists in self.url server.

Returns response from server as JSON dict or None if endpoint is not found
"""

resp = self.get(f"/v1/workspace/{workspace_id}/usage")
return json.load(resp)

def server_type(self):
"""
Returns the deployment type of the server
Expand Down Expand Up @@ -700,41 +711,84 @@ def project_info(self, project_path_or_id, since=None, version=None):
resp = self.get("/v1/project/{}".format(project_path_or_id), params)
return json.load(resp)

def project_versions(self, project_path, since=None, to=None):
def paginated_project_versions(self, project_path, page, per_page=100, descending=False):
"""
Get records of project's versions (history) using calculated pagination.
wrapper around the /v1/project/versions/paginated/{} API end point

:param project_path: Project's full name (<namespace>/<name>)
:type project_path: String | Int
:param page: page number
:type page: Int
:param per_page: number of results per page default 100
:type per_page: Int
:param descending: order of sorting
:type descending: Bool

:rtype: List[Dict], Int
"""
params = {"page": page, "per_page": per_page, "descending": descending}
resp = self.get("/v1/project/versions/paginated/{}".format(project_path), params)
resp_json = json.load(resp)
return resp_json["versions"], resp_json["count"]

def project_versions_count(self, project_path):
"""
return the total count of versions
To note we fetch only one page and one item as we only need the "count" response

:param project_path_or_id: Project's full name (<namespace>/<name>) or id
:type project_path_or_id: String

:rtype: Int
"""
params = {"page": 1, "per_page": 1, "descending": False}
resp = self.get("/v1/project/versions/paginated/{}".format(project_path), params)
resp_json = json.load(resp)
return resp_json["count"]

def project_versions(self, project_path, since=1, to=None):
"""
Get records of project's versions (history) in ascending order.
If neither 'since' nor 'to' is specified it will return all versions.

:param project_path: Project's full name (<namespace>/<name>)
:type project_path: String
:param since: Version to track project history from
:type since: String
:type since: String | Int
:param to: Version to track project history to
:type to: String
:type to: String | Int

:rtype: List[Dict]
"""
versions = []
per_page = 100 # server limit
num_since = int_version(since) if since else 1
num_to = int_version(to) if to else None # we may not know yet

if type(since) == str:
num_since = int_version(since)
else:
# keep the since parameter as is
num_since = since

if type(to) == str:
num_to = int_version(to)
else:
# keep the to parameter as is
num_to = to

start_page = math.ceil(num_since / per_page)
if not num_to:
# let's get first page and count
params = {"page": start_page, "per_page": per_page, "descending": False}
resp = self.get("/v1/project/versions/paginated/{}".format(project_path), params)
resp_json = json.load(resp)
versions = resp_json["versions"]
num_to = resp_json["count"]
versions, num_to = self.paginated_project_versions(project_path, start_page, per_page)

latest_version = int_version(versions[-1]["name"])
if latest_version < num_to:
versions += self.project_versions(project_path, f"v{latest_version+1}", f"v{num_to}")
else:
end_page = math.ceil(num_to / per_page)
for page in range(start_page, end_page + 1):
params = {"page": page, "per_page": per_page, "descending": False}
resp = self.get("/v1/project/versions/paginated/{}".format(project_path), params)
versions += json.load(resp)["versions"]
page_versions, _ = self.paginated_project_versions(project_path, page, per_page)
versions += page_versions

# filter out versions not within range
filtered_versions = list(filter(lambda v: (num_since <= int_version(v["name"]) <= num_to), versions))
Expand Down
2 changes: 2 additions & 0 deletions mergin/client_pull.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,8 @@ def download_diffs_async(mc, project_directory, file_path, versions):
fetch_files = []

for version in versions:
if version not in file_history["history"]:
continue # skip if this file was not modified at this version
version_data = file_history["history"][version]
if "diff" not in version_data:
continue # skip if there is no diff in history
Expand Down
8 changes: 8 additions & 0 deletions mergin/test/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2013,6 +2013,14 @@ def test_project_versions_list(mc):
assert versions[0]["name"] == "v2"
assert versions[-1]["name"] == "v4"

versions_count = mc.project_versions_count(project)
assert versions_count == 5

versions, _ = mc.paginated_project_versions(project, page=1, descending=True)
assert len(versions) == 5
assert versions[0]["name"] == "v5"
assert versions[-1]["name"] == "v1"


def test_report(mc):
test_project = "test_report"
Expand Down
Loading