diff --git a/mergin/client.py b/mergin/client.py index f5062aca..14ebe033 100644 --- a/mergin/client.py +++ b/mergin/client.py @@ -519,15 +519,7 @@ def create_project_and_push(self, project_name, directory, is_public=False, name self.create_project(project_name, is_public) if directory: project_info = self.project_info(project_name) - MerginProject.write_metadata( - directory, - { - "name": project_name, - "version": "v0", - "files": [], - "project_id": project_info["id"], - }, - ) + MerginProject.write_metadata(directory, project_info) mp = MerginProject(directory) if mp.inspect_files(): self.push_project(directory) diff --git a/mergin/client_pull.py b/mergin/client_pull.py index 0b1b5ef3..7baf9463 100644 --- a/mergin/client_pull.py +++ b/mergin/client_pull.py @@ -215,15 +215,7 @@ def download_project_finalize(job): task.apply(job.directory, job.mp) # final update of project metadata - # TODO: why not exact copy of project info JSON ? - job.mp.update_metadata( - { - "name": job.project_path, - "version": job.version, - "project_id": job.project_info["id"], - "files": job.project_info["files"], - } - ) + job.mp.update_metadata(job.project_info) def download_project_cancel(job): @@ -613,14 +605,7 @@ def pull_project_finalize(job): job.mp.log.info("--- pull aborted") raise ClientError("Failed to apply pull changes: " + str(e)) - job.mp.update_metadata( - { - "name": job.project_path, - "version": job.version if job.version else "v0", # for new projects server version is "" - "project_id": job.project_info["id"], - "files": job.project_info["files"], - } - ) + job.mp.update_metadata(job.project_info) if job.mp.has_unfinished_pull(): job.mp.log.info("--- failed to complete pull -- project left in the unfinished pull state") diff --git a/mergin/client_push.py b/mergin/client_push.py index 1c357715..de48fc16 100644 --- a/mergin/client_push.py +++ b/mergin/client_push.py @@ -272,14 +272,7 @@ def push_project_finalize(job): job.mp.log.info("cancel response: " + str(err2)) raise err - job.mp.update_metadata( - { - "name": job.project_path, - "version": job.server_resp["version"], - "project_id": job.server_resp["id"], - "files": job.server_resp["files"], - } - ) + job.mp.update_metadata(job.server_resp) try: job.mp.apply_push_changes(job.changes) except Exception as e: diff --git a/mergin/merginproject.py b/mergin/merginproject.py index 93fa7206..1cd3fa91 100644 --- a/mergin/merginproject.py +++ b/mergin/merginproject.py @@ -58,6 +58,7 @@ def __init__(self, directory): # metadata from JSON are lazy loaded self._metadata = None + self.is_old_metadata = False self.setup_logging(directory) @@ -139,7 +140,10 @@ def project_full_name(self) -> str: """Returns fully qualified project name: /""" if self._metadata is None: self._read_metadata() - return self._metadata["name"] + if self.is_old_metadata: + return self._metadata["name"] + else: + return f"{self._metadata['namespace']}/{self._metadata['name']}" def project_name(self) -> str: """Returns only project name, without its workspace name""" @@ -154,10 +158,25 @@ def workspace_name(self) -> str: return full_name[:slash_index] def project_id(self) -> str: - """Returns ID of the project (UUID using 8-4-4-4-12 formatting without braces)""" + """Returns ID of the project (UUID using 8-4-4-4-12 formatting without braces) + + Raises ClientError if project id is not present in the project metadata. This should + only happen with projects downloaded with old client, before February 2023, + see https://github.com/MerginMaps/mergin-py-client/pull/154 + """ if self._metadata is None: self._read_metadata() - return self._metadata["project_id"] + + # "id" or "project_id" may not exist in projects downloaded with old client version + if self.is_old_metadata: + if "project_id" not in self._metadata: + raise ClientError( + "The project directory has been created with an old version of the Mergin Maps client. " + "Please delete the project directory and re-download the project." + ) + return self._metadata["project_id"] + else: + return self._metadata["id"] def workspace_id(self) -> int: """Returns ID of the workspace where the project belongs""" @@ -196,6 +215,8 @@ def _read_metadata(self): with open(self.fpath_meta("mergin.json"), "r") as file: self._metadata = json.load(file) + self.is_old_metadata = "/" in self._metadata["name"] + def update_metadata(self, data: dict): """Writes project metadata and updates cached metadata.""" self._metadata = data diff --git a/mergin/test/test_client.py b/mergin/test/test_client.py index febededf..36cbd0d2 100644 --- a/mergin/test/test_client.py +++ b/mergin/test/test_client.py @@ -2003,3 +2003,38 @@ def test_clean_diff_files(mc): diff_files = glob.glob("*-diff-*", root_dir=os.path.split(mp.fpath_meta("inserted_1_A.gpkg"))[0]) assert diff_files == [] + + +def test_project_metadata(mc): + test_project = "test_project_metadata" + project = API_USER + "/" + test_project + project_dir = os.path.join(TMP_DIR, test_project) + + cleanup(mc, project, [project_dir]) + + # prepare local project + shutil.copytree(TEST_DATA_DIR, project_dir) + + # copy metadata in old format + os.makedirs(os.path.join(project_dir, ".mergin"), exist_ok=True) + project_metadata = os.path.join(project_dir, ".mergin", "mergin.json") + metadata_file = os.path.join(project_dir, "old_metadata.json") + shutil.copyfile(metadata_file, project_metadata) + + # verify we have correct metadata + mp = MerginProject(project_dir) + assert mp.project_full_name() == f"{API_USER}/{test_project}" + assert mp.project_name() == test_project + assert mp.workspace_name() == API_USER + assert mp.version() == "v0" + + # copy metadata in new format + metadata_file = os.path.join(project_dir, "new_metadata.json") + shutil.copyfile(metadata_file, project_metadata) + + # verify we have correct metadata + mp = MerginProject(project_dir) + assert mp.project_full_name() == f"{API_USER}/{test_project}" + assert mp.project_name() == test_project + assert mp.workspace_name() == API_USER + assert mp.version() == "v0" diff --git a/mergin/test/test_data/new_metadata.json b/mergin/test/test_data/new_metadata.json new file mode 100644 index 00000000..5dcb4ff9 --- /dev/null +++ b/mergin/test/test_data/new_metadata.json @@ -0,0 +1,43 @@ +{ + "access": { + "owners": [ + 2 + ], + "ownersnames": [ + "test_plugin" + ], + "public": false, + "readers": [ + 2 + ], + "readersnames": [ + "test_plugin" + ], + "writers": [ + 2 + ], + "writersnames": [ + "test_plugin" + ] + }, + "created": "2023-10-16T09:17:27Z", + "creator": 2, + "disk_usage": 0, + "files": [], + "id": "a6f9d38c-e30d-49f2-bfc5-76495afdbf27", + "name": "test_project_metadata", + "namespace": "test_plugin", + "permissions": { + "delete": true, + "update": true, + "upload": true + }, + "removed_at": null, + "removed_by": null, + "role": "owner", + "tags": [], + "updated": "2023-10-16T09:17:27.345127", + "uploads": [], + "version": "v0", + "workspace_id": 18 +} \ No newline at end of file diff --git a/mergin/test/test_data/old_metadata.json b/mergin/test/test_data/old_metadata.json new file mode 100644 index 00000000..8363ad0d --- /dev/null +++ b/mergin/test/test_data/old_metadata.json @@ -0,0 +1,6 @@ +{ + "name": "test_plugin/test_project_metadata", + "version": "v0", + "project_id": "effeca08-ef22-4fc1-b620-5261c6a081eb", + "files": [] +}