Loading trapper/trapper-project/trapper/apps/media_classification/tasks/data_packages.py +104 −51 Original line number Diff line number Diff line Loading @@ -411,86 +411,139 @@ class ResultsDataPackageGenerator: class PublishDataPackage: """ TODO: docstrings Publishes a data package to external repositories (Dataverse or Zenodo). """ def __init__(self, data, user): self.user = user self.data = data self.token = data["api_token"] self.host = data["host_url"] self.secure = data.get("secure_connection", True) self.data_hub = data["data_hub"] self.data_package = data["data_package"] def _get_error_message(self, response): """Extract error message from response with fallback handling.""" try: return response.json().get("message", response.text) except (json.JSONDecodeError, ValueError): return f"HTTP {response.status_code}: {response.text[:200]}" def run(self): # connection settings token = self.data["api_token"] host = self.data["host_url"] secure = self.data["secure_connection"] # get zipped data package data_package = self.data["data_package"] zipped = zipfile.ZipFile(open(data_package.package.path, "rb")) # process package descriptor def _open_package(self): """Open and validate the data package.""" try: zipped = zipfile.ZipFile(open(self.data_package.package.path, "rb")) descriptor = json.loads(zipped.read("datapackage.json")) if self.data["data_hub"] == "Dataverse": return zipped, descriptor except (zipfile.BadZipFile, KeyError) as e: raise ValueError(f"Invalid data package: {e}") except json.JSONDecodeError as e: raise ValueError(f"Invalid package descriptor JSON: {e}") def _publish_to_dataverse(self, zipped, descriptor): """Publish package to Dataverse.""" dv_meta, dfiles = mapper.package2dataverse(descriptor, taxonomic_cov=False) dv_meta_json = json.dumps(dv_meta) # create dataset dataverse = self.data["container"] url = f"{host}/api/dataverses/{dataverse}/datasets" headers = {"X-Dataverse-key": token, "Content-Type": "application/json"} resp = requests.post(url, data=dv_meta_json, headers=headers, verify=secure) if resp.status_code == 201: # Create dataset url = f"{self.host}/api/dataverses/{dataverse}/datasets" headers = {"X-Dataverse-key": self.token, "Content-Type": "application/json"} resp = requests.post( url, data=json.dumps(dv_meta), headers=headers, verify=self.secure ) if resp.status_code != 201: raise Exception( f"Failed to create dataset: {self._get_error_message(resp)}" ) dataset_data = resp.json()["data"] dataset_id = dataset_data["id"] # upload files url = f"{host}/api/datasets/{dataset_id}/add" # Upload files url = f"{self.host}/api/datasets/{dataset_id}/add" for fdesc in dfiles: try: files = {"file": zipped.open(fdesc["filename"])} payload = dict(jsonData=json.dumps(fdesc)) payload = {"jsonData": json.dumps(fdesc)} resp = requests.post( url, data=payload, files=files, params={"key": token}, verify=secure, params={"key": self.token}, verify=self.secure, ) if resp.status_code not in (200, 201): raise Exception( f"Failed to upload {fdesc['filename']}: {self._get_error_message(resp)}" ) time.sleep(2) else: raise Exception(resp.json()["message"]) msg = _( f"You have successfully published your data package {data_package.filename()} at " f"{host} ! Details of the published dataset: {dataset_data}" except KeyError as e: raise Exception( f"File {fdesc.get('filename', 'unknown')} not found in package: {e}" ) return msg elif self.data["data_hub"] == "Zenodo": # get package metadata in zenodo-friendly format and files list meta, datafiles = mapper.package2zenodo(descriptor) return _( f"Successfully published data package {self.data_package.filename()} to {self.host}. " f"Dataset ID: {dataset_id}" ) params = {"access_token": token} def _publish_to_zenodo(self, zipped, descriptor): """Publish package to Zenodo.""" meta, datafiles = mapper.package2zenodo(descriptor) params = {"access_token": self.token} # upload files # Upload files for fname in datafiles: fcontent = zipped.open(fname) r = requests.put( "%s/%s" % (host, fname), data=fcontent, params=params, try: with zipped.open(fname) as fcontent: url = f"{self.host}/{fname}" resp = requests.put(url, data=fcontent, params=params) if resp.status_code != 200: raise Exception( f"Failed to upload {fname}: {self._get_error_message(resp)}" ) if r.status_code != 200: raise Exception(r.json()["message"]) except KeyError as e: raise Exception(f"File {fname} not found in package: {e}") # send metadata # Send metadata headers = {"Content-Type": "application/json"} metadata_url = self.data["metadata_url"] r = requests.put( metadata_url, params=params, data=json.dumps(meta), headers=headers resp = requests.put( metadata_url, params=params, data=json.dumps(meta), headers=headers, ) if r.status_code != 200: raise Exception(r.json()["message"]) msg = _( "You have successfully sent data package to Zenodo. It can be published manually from your " "Zenodo account." if resp.status_code != 200: raise Exception( f"Failed to update metadata: {self._get_error_message(resp)}" ) return msg raise NotImplementedError return _( "Successfully sent data package to Zenodo. " "It can be published manually from your Zenodo account." ) def run(self): """Execute the publishing workflow.""" zipped, descriptor = self._open_package() try: if self.data_hub == "Dataverse": return self._publish_to_dataverse(zipped, descriptor) elif self.data_hub == "Zenodo": return self._publish_to_zenodo(zipped, descriptor) else: raise NotImplementedError( f"Publishing to {self.data_hub} is not supported" ) finally: zipped.close() trapper/trapper-project/trapper/apps/storage/models.py +2 −7 Original line number Diff line number Diff line Loading @@ -324,13 +324,8 @@ class Resource(AccessModelMixin, models.Model): if Deployment.objects.filter(pk=self.deployment_id, managers=user).exists(): return True # Membership in any collection that contains this resource, excluding owner/manager roles if ( self.collection_set.exclude(owner=user) .exclude(managers=user) .filter(members=user) .exists() ): # Membership in any collection that contains this resource if self.collection_set.filter(members=user).exists(): return True # Membership in any CS Team that contains this resource's deployment Loading Loading
trapper/trapper-project/trapper/apps/media_classification/tasks/data_packages.py +104 −51 Original line number Diff line number Diff line Loading @@ -411,86 +411,139 @@ class ResultsDataPackageGenerator: class PublishDataPackage: """ TODO: docstrings Publishes a data package to external repositories (Dataverse or Zenodo). """ def __init__(self, data, user): self.user = user self.data = data self.token = data["api_token"] self.host = data["host_url"] self.secure = data.get("secure_connection", True) self.data_hub = data["data_hub"] self.data_package = data["data_package"] def _get_error_message(self, response): """Extract error message from response with fallback handling.""" try: return response.json().get("message", response.text) except (json.JSONDecodeError, ValueError): return f"HTTP {response.status_code}: {response.text[:200]}" def run(self): # connection settings token = self.data["api_token"] host = self.data["host_url"] secure = self.data["secure_connection"] # get zipped data package data_package = self.data["data_package"] zipped = zipfile.ZipFile(open(data_package.package.path, "rb")) # process package descriptor def _open_package(self): """Open and validate the data package.""" try: zipped = zipfile.ZipFile(open(self.data_package.package.path, "rb")) descriptor = json.loads(zipped.read("datapackage.json")) if self.data["data_hub"] == "Dataverse": return zipped, descriptor except (zipfile.BadZipFile, KeyError) as e: raise ValueError(f"Invalid data package: {e}") except json.JSONDecodeError as e: raise ValueError(f"Invalid package descriptor JSON: {e}") def _publish_to_dataverse(self, zipped, descriptor): """Publish package to Dataverse.""" dv_meta, dfiles = mapper.package2dataverse(descriptor, taxonomic_cov=False) dv_meta_json = json.dumps(dv_meta) # create dataset dataverse = self.data["container"] url = f"{host}/api/dataverses/{dataverse}/datasets" headers = {"X-Dataverse-key": token, "Content-Type": "application/json"} resp = requests.post(url, data=dv_meta_json, headers=headers, verify=secure) if resp.status_code == 201: # Create dataset url = f"{self.host}/api/dataverses/{dataverse}/datasets" headers = {"X-Dataverse-key": self.token, "Content-Type": "application/json"} resp = requests.post( url, data=json.dumps(dv_meta), headers=headers, verify=self.secure ) if resp.status_code != 201: raise Exception( f"Failed to create dataset: {self._get_error_message(resp)}" ) dataset_data = resp.json()["data"] dataset_id = dataset_data["id"] # upload files url = f"{host}/api/datasets/{dataset_id}/add" # Upload files url = f"{self.host}/api/datasets/{dataset_id}/add" for fdesc in dfiles: try: files = {"file": zipped.open(fdesc["filename"])} payload = dict(jsonData=json.dumps(fdesc)) payload = {"jsonData": json.dumps(fdesc)} resp = requests.post( url, data=payload, files=files, params={"key": token}, verify=secure, params={"key": self.token}, verify=self.secure, ) if resp.status_code not in (200, 201): raise Exception( f"Failed to upload {fdesc['filename']}: {self._get_error_message(resp)}" ) time.sleep(2) else: raise Exception(resp.json()["message"]) msg = _( f"You have successfully published your data package {data_package.filename()} at " f"{host} ! Details of the published dataset: {dataset_data}" except KeyError as e: raise Exception( f"File {fdesc.get('filename', 'unknown')} not found in package: {e}" ) return msg elif self.data["data_hub"] == "Zenodo": # get package metadata in zenodo-friendly format and files list meta, datafiles = mapper.package2zenodo(descriptor) return _( f"Successfully published data package {self.data_package.filename()} to {self.host}. " f"Dataset ID: {dataset_id}" ) params = {"access_token": token} def _publish_to_zenodo(self, zipped, descriptor): """Publish package to Zenodo.""" meta, datafiles = mapper.package2zenodo(descriptor) params = {"access_token": self.token} # upload files # Upload files for fname in datafiles: fcontent = zipped.open(fname) r = requests.put( "%s/%s" % (host, fname), data=fcontent, params=params, try: with zipped.open(fname) as fcontent: url = f"{self.host}/{fname}" resp = requests.put(url, data=fcontent, params=params) if resp.status_code != 200: raise Exception( f"Failed to upload {fname}: {self._get_error_message(resp)}" ) if r.status_code != 200: raise Exception(r.json()["message"]) except KeyError as e: raise Exception(f"File {fname} not found in package: {e}") # send metadata # Send metadata headers = {"Content-Type": "application/json"} metadata_url = self.data["metadata_url"] r = requests.put( metadata_url, params=params, data=json.dumps(meta), headers=headers resp = requests.put( metadata_url, params=params, data=json.dumps(meta), headers=headers, ) if r.status_code != 200: raise Exception(r.json()["message"]) msg = _( "You have successfully sent data package to Zenodo. It can be published manually from your " "Zenodo account." if resp.status_code != 200: raise Exception( f"Failed to update metadata: {self._get_error_message(resp)}" ) return msg raise NotImplementedError return _( "Successfully sent data package to Zenodo. " "It can be published manually from your Zenodo account." ) def run(self): """Execute the publishing workflow.""" zipped, descriptor = self._open_package() try: if self.data_hub == "Dataverse": return self._publish_to_dataverse(zipped, descriptor) elif self.data_hub == "Zenodo": return self._publish_to_zenodo(zipped, descriptor) else: raise NotImplementedError( f"Publishing to {self.data_hub} is not supported" ) finally: zipped.close()
trapper/trapper-project/trapper/apps/storage/models.py +2 −7 Original line number Diff line number Diff line Loading @@ -324,13 +324,8 @@ class Resource(AccessModelMixin, models.Model): if Deployment.objects.filter(pk=self.deployment_id, managers=user).exists(): return True # Membership in any collection that contains this resource, excluding owner/manager roles if ( self.collection_set.exclude(owner=user) .exclude(managers=user) .filter(members=user) .exists() ): # Membership in any collection that contains this resource if self.collection_set.filter(members=user).exists(): return True # Membership in any CS Team that contains this resource's deployment Loading