das-cli 1.2.33__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {das_cli-1.2.33/das_cli.egg-info → das_cli-1.3.0}/PKG-INFO +44 -1
  2. {das_cli-1.2.33 → das_cli-1.3.0}/README.md +43 -0
  3. {das_cli-1.2.33 → das_cli-1.3.0}/das/cli.py +43 -0
  4. {das_cli-1.2.33 → das_cli-1.3.0}/das/managers/digital_objects_manager.py +37 -0
  5. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/digital_objects.py +58 -1
  6. {das_cli-1.2.33 → das_cli-1.3.0/das_cli.egg-info}/PKG-INFO +44 -1
  7. {das_cli-1.2.33 → das_cli-1.3.0}/pyproject.toml +1 -1
  8. {das_cli-1.2.33 → das_cli-1.3.0}/LICENSE +0 -0
  9. {das_cli-1.2.33 → das_cli-1.3.0}/MANIFEST.in +0 -0
  10. {das_cli-1.2.33 → das_cli-1.3.0}/das/__init__.py +0 -0
  11. {das_cli-1.2.33 → das_cli-1.3.0}/das/ai/plugins/dasai.py +0 -0
  12. {das_cli-1.2.33 → das_cli-1.3.0}/das/ai/plugins/entries/entries_plugin.py +0 -0
  13. {das_cli-1.2.33 → das_cli-1.3.0}/das/app.py +0 -0
  14. {das_cli-1.2.33 → das_cli-1.3.0}/das/authentication/auth.py +0 -0
  15. {das_cli-1.2.33 → das_cli-1.3.0}/das/authentication/oauth.py +0 -0
  16. {das_cli-1.2.33 → das_cli-1.3.0}/das/authentication/secure_input.py +0 -0
  17. {das_cli-1.2.33 → das_cli-1.3.0}/das/common/api.py +0 -0
  18. {das_cli-1.2.33 → das_cli-1.3.0}/das/common/config.py +0 -0
  19. {das_cli-1.2.33 → das_cli-1.3.0}/das/common/entry_fields_constants.py +0 -0
  20. {das_cli-1.2.33 → das_cli-1.3.0}/das/common/enums.py +0 -0
  21. {das_cli-1.2.33 → das_cli-1.3.0}/das/common/file_utils.py +0 -0
  22. {das_cli-1.2.33 → das_cli-1.3.0}/das/managers/__init__.py +0 -0
  23. {das_cli-1.2.33 → das_cli-1.3.0}/das/managers/download_manager.py +0 -0
  24. {das_cli-1.2.33 → das_cli-1.3.0}/das/managers/entries_manager.py +0 -0
  25. {das_cli-1.2.33 → das_cli-1.3.0}/das/managers/search_manager.py +0 -0
  26. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/attributes.py +0 -0
  27. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/cache.py +0 -0
  28. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/downloads.py +0 -0
  29. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/entries.py +0 -0
  30. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/entry_fields.py +0 -0
  31. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/hangfire.py +0 -0
  32. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/search.py +0 -0
  33. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/service_base.py +0 -0
  34. {das_cli-1.2.33 → das_cli-1.3.0}/das/services/users.py +0 -0
  35. {das_cli-1.2.33 → das_cli-1.3.0}/das_cli.egg-info/SOURCES.txt +0 -0
  36. {das_cli-1.2.33 → das_cli-1.3.0}/das_cli.egg-info/dependency_links.txt +0 -0
  37. {das_cli-1.2.33 → das_cli-1.3.0}/das_cli.egg-info/entry_points.txt +0 -0
  38. {das_cli-1.2.33 → das_cli-1.3.0}/das_cli.egg-info/requires.txt +0 -0
  39. {das_cli-1.2.33 → das_cli-1.3.0}/das_cli.egg-info/top_level.txt +0 -0
  40. {das_cli-1.2.33 → das_cli-1.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: das-cli
3
- Version: 1.2.33
3
+ Version: 1.3.0
4
4
  Summary: DAS api client.
5
5
  Author: Royal Netherlands Institute for Sea Research
6
6
  License-Expression: MIT
@@ -185,6 +185,16 @@ das entry update --attribute <AttributeName> [--code CODE] <file_path>
185
185
  das entry upload-digital-object --entry-code ENT001 --type Dataset --description "CTD raw" c:\data\ctd.zip
186
186
  ```
187
187
 
188
+ #### Direct download a digital object
189
+
190
+ ```bash
191
+ # Download by entry and digital object codes
192
+ das entry direct-download-digital-object --entry-code ENT001 --digital-object-code DO001 --out C:\Downloads\
193
+
194
+ # Download by IDs
195
+ das entry direct-download-digital-object --entry-id e1987f3e-7db7-11f0-a7e8-0edcca226f3d --attribute-id 126 --digital-object-id cf335b17-80e3-4151-aa80-40b69fe0567e --out C:\Downloads\file.bin
196
+ ```
197
+
188
198
  #### Link or unlink digital objects
189
199
 
190
200
  ```bash
@@ -925,6 +935,39 @@ digital_object_id = digital_objects_manager.upload_digital_object(
925
935
  )
926
936
  ```
927
937
 
938
+ #### Direct Download Digital Object
939
+
940
+ **CLI:**
941
+ ```bash
942
+ # Download by entry and digital object codes
943
+ das entry direct-download-digital-object --entry-code ENT001 --digital-object-code DO001 --out C:\Downloads\
944
+
945
+ # Download by IDs
946
+ das entry direct-download-digital-object --entry-id e1987f3e-7db7-11f0-a7e8-0edcca226f3d --attribute-id 126 --digital-object-id cf335b17-80e3-4151-aa80-40b69fe0567e --out C:\Downloads\file.bin
947
+ ```
948
+
949
+ **Manager Layer:**
950
+ ```python
951
+ from das.managers.digital_objects_manager import DigitalObjectsManager
952
+
953
+ digital_objects_manager = DigitalObjectsManager()
954
+
955
+ # Download by codes
956
+ saved_path = digital_objects_manager.direct_download_digital_object(
957
+ entry_code="ENT001",
958
+ digital_object_code="DO001",
959
+ output_path="C:\\Downloads\\"
960
+ )
961
+
962
+ # Download by IDs
963
+ saved_path = digital_objects_manager.direct_download_digital_object(
964
+ entry_id="e1987f3e-7db7-11f0-a7e8-0edcca226f3d",
965
+ attribute_id=126,
966
+ digital_object_id="cf335b17-80e3-4151-aa80-40b69fe0567e",
967
+ output_path="C:\\Downloads\\file.bin"
968
+ )
969
+ ```
970
+
928
971
  #### Link/Unlink Digital Objects
929
972
 
930
973
  **CLI:**
@@ -162,6 +162,16 @@ das entry update --attribute <AttributeName> [--code CODE] <file_path>
162
162
  das entry upload-digital-object --entry-code ENT001 --type Dataset --description "CTD raw" c:\data\ctd.zip
163
163
  ```
164
164
 
165
+ #### Direct download a digital object
166
+
167
+ ```bash
168
+ # Download by entry and digital object codes
169
+ das entry direct-download-digital-object --entry-code ENT001 --digital-object-code DO001 --out C:\Downloads\
170
+
171
+ # Download by IDs
172
+ das entry direct-download-digital-object --entry-id e1987f3e-7db7-11f0-a7e8-0edcca226f3d --attribute-id 126 --digital-object-id cf335b17-80e3-4151-aa80-40b69fe0567e --out C:\Downloads\file.bin
173
+ ```
174
+
165
175
  #### Link or unlink digital objects
166
176
 
167
177
  ```bash
@@ -902,6 +912,39 @@ digital_object_id = digital_objects_manager.upload_digital_object(
902
912
  )
903
913
  ```
904
914
 
915
+ #### Direct Download Digital Object
916
+
917
+ **CLI:**
918
+ ```bash
919
+ # Download by entry and digital object codes
920
+ das entry direct-download-digital-object --entry-code ENT001 --digital-object-code DO001 --out C:\Downloads\
921
+
922
+ # Download by IDs
923
+ das entry direct-download-digital-object --entry-id e1987f3e-7db7-11f0-a7e8-0edcca226f3d --attribute-id 126 --digital-object-id cf335b17-80e3-4151-aa80-40b69fe0567e --out C:\Downloads\file.bin
924
+ ```
925
+
926
+ **Manager Layer:**
927
+ ```python
928
+ from das.managers.digital_objects_manager import DigitalObjectsManager
929
+
930
+ digital_objects_manager = DigitalObjectsManager()
931
+
932
+ # Download by codes
933
+ saved_path = digital_objects_manager.direct_download_digital_object(
934
+ entry_code="ENT001",
935
+ digital_object_code="DO001",
936
+ output_path="C:\\Downloads\\"
937
+ )
938
+
939
+ # Download by IDs
940
+ saved_path = digital_objects_manager.direct_download_digital_object(
941
+ entry_id="e1987f3e-7db7-11f0-a7e8-0edcca226f3d",
942
+ attribute_id=126,
943
+ digital_object_id="cf335b17-80e3-4151-aa80-40b69fe0567e",
944
+ output_path="C:\\Downloads\\file.bin"
945
+ )
946
+ ```
947
+
905
948
  #### Link/Unlink Digital Objects
906
949
 
907
950
  **CLI:**
@@ -724,6 +724,49 @@ def upload_digital_object(das_ctx, entry_code, digital_object_type, file_descrip
724
724
  except Exception as e:
725
725
  click.secho(f"Error: {e}", fg="red")
726
726
 
727
+ @entry.command("direct-download-digital-object")
728
+ @click.option('--entry-code', default=None, help='Entry code containing the digital object')
729
+ @click.option('--entry-id', default=None, help='Entry ID containing the digital object')
730
+ @click.option('--attribute-id', type=int, default=None, help='Attribute ID for the entry (required with --entry-id)')
731
+ @click.option('--digital-object-code', default=None, help='Digital object code to download')
732
+ @click.option('--digital-object-id', default=None, help='Digital object ID to download')
733
+ @click.option('--out', 'output_path', required=True, help='Output file path or output directory')
734
+ @pass_das_context
735
+ def direct_download_digital_object(das_ctx, entry_code, entry_id, attribute_id, digital_object_code, digital_object_id, output_path):
736
+ """Directly download a digital object by codes or IDs.
737
+
738
+ Examples:
739
+
740
+ \b
741
+ # Download using entry and digital object codes
742
+ das entry direct-download-digital-object --entry-code ENT001 --digital-object-code DO001 --out C:\\Downloads\\
743
+
744
+ \b
745
+ # Download using IDs
746
+ das entry direct-download-digital-object --entry-id e1987f3e-7db7-11f0-a7e8-0edcca226f3d --attribute-id 126 --digital-object-id cf335b17-80e3-4151-aa80-40b69fe0567e --out C:\\Downloads\\file.bin
747
+ """
748
+ try:
749
+ das_ctx.get_client()
750
+
751
+ if not entry_code and not entry_id:
752
+ raise click.UsageError("Please provide either --entry-code or --entry-id")
753
+ if not digital_object_code and not digital_object_id:
754
+ raise click.UsageError("Please provide either --digital-object-code or --digital-object-id")
755
+ if entry_id and not attribute_id:
756
+ raise click.UsageError("--attribute-id is required when using --entry-id")
757
+
758
+ saved_path = das_ctx.digital_objects_manager.direct_download_digital_object(
759
+ entry_code=entry_code,
760
+ entry_id=entry_id,
761
+ attribute_id=attribute_id,
762
+ digital_object_id=digital_object_id,
763
+ digital_object_code=digital_object_code,
764
+ output_path=output_path,
765
+ )
766
+ click.secho(f"✓ Digital object saved to: {saved_path}", fg="green")
767
+ except Exception as e:
768
+ click.secho(f"Error: {e}", fg="red")
769
+
727
770
  @entry.command("get")
728
771
  @click.option('--code', default=None, help='Entry code')
729
772
  @click.option('--id', type=int, default=None, help='Entry ID')
@@ -78,6 +78,43 @@ class DigitalObjectsManager:
78
78
 
79
79
  return digital_object_id
80
80
 
81
+
82
+ def direct_download_digital_object(self,
83
+ entry_code: str = None,
84
+ entry_id: str = None,
85
+ attribute_id: int = None,
86
+ digital_object_id: str = None,
87
+ digital_object_code: str = None,
88
+ output_path: str = None):
89
+ """Directly download a digital object from the digital object service."""
90
+ if not output_path:
91
+ raise ValueError("Output path is required")
92
+ if entry_code:
93
+ entry_response = self.entry_service.get_entry(entry_code)
94
+ if entry_response is None:
95
+ raise ValueError(f"Entry with code '{entry_code}' not found")
96
+ if entry_response.get('attributeId') is None:
97
+ raise ValueError(f"Entry with code '{entry_code}' has no attributeId")
98
+ entry_id = entry_response.get('entry').get('id')
99
+ attribute_id = entry_response.get('attributeId')
100
+ if digital_object_code:
101
+ digital_object_response = self.entry_service.get_entry(digital_object_code)
102
+ if digital_object_response is None:
103
+ raise ValueError(f"Digital object with code '{digital_object_code}' not found")
104
+ if digital_object_response.get('attributeId') is None:
105
+ raise ValueError(f"Digital object with code '{digital_object_code}' has no attributeId")
106
+ digital_object_id = digital_object_response.get('entry').get('id')
107
+
108
+ if not entry_id or not attribute_id or not digital_object_id:
109
+ raise ValueError("Entry ID, attribute ID, and digital object ID are required")
110
+
111
+ return self.digital_objects_service.direct_download_digital_object(
112
+ entry_id=entry_id,
113
+ attribute_id=attribute_id,
114
+ digital_object_id=digital_object_id,
115
+ output_path=output_path
116
+ )
117
+
81
118
 
82
119
  if __name__ == "__main__":
83
120
  digital_objects_manager = DigitalObjectsManager()
@@ -2,7 +2,7 @@ import os
2
2
  from math import ceil
3
3
  from os.path import exists
4
4
  import json
5
- from base64 import b64encode
5
+ from base64 import b64encode, b64decode
6
6
  from das.common.api import post_data
7
7
  from das.common.config import load_verify_ssl
8
8
  from das.services.service_base import ServiceBase
@@ -123,3 +123,60 @@ class DigitalObjectsService(ServiceBase):
123
123
  raise ValueError(f"Error uploading file: {response.status_code} - {response.text}")
124
124
  except requests.RequestException as e:
125
125
  raise ValueError(f"Error uploading file: {str(e)}")
126
+
127
+
128
+ def direct_download_digital_object(self, entry_id: str, attribute_id: int, digital_object_id: str, output_path: str):
129
+ """Directly download a digital object from the digital object service."""
130
+ headers = {**self.set_auth_headers(), "Content-Type": "application/json"}
131
+
132
+ url = f"{self.base_url}/GetDigitalObjectsFromEntry"
133
+
134
+ payload = {
135
+ "attributeId": attribute_id,
136
+ "entryId": entry_id,
137
+ "digitalObjectId": digital_object_id
138
+ }
139
+
140
+ response = post_data(url, data=payload, headers=headers)
141
+ if response.get("success") != True:
142
+ raise ValueError(response.get("error") or "Unknown error occurred")
143
+
144
+ result = response.get("result") or {}
145
+ digital_object_item = result.get("digitalObjectItem") or {}
146
+ data = digital_object_item.get("data")
147
+ display_name = digital_object_item.get("displayName")
148
+
149
+ if data is None:
150
+ raise ValueError("Digital object data was not returned by the API")
151
+
152
+ file_bytes = None
153
+ if isinstance(data, str):
154
+ try:
155
+ file_bytes = b64decode(data, validate=False)
156
+ except Exception as e:
157
+ raise ValueError(f"Invalid base64 digital object data: {str(e)}")
158
+ elif isinstance(data, (bytes, bytearray)):
159
+ file_bytes = bytes(data)
160
+ else:
161
+ raise ValueError("Unsupported digital object data format")
162
+
163
+ is_directory_target = (
164
+ output_path.endswith(os.sep)
165
+ or output_path.endswith("/")
166
+ or output_path.endswith("\\")
167
+ or os.path.isdir(output_path)
168
+ )
169
+
170
+ if is_directory_target:
171
+ if not display_name:
172
+ raise ValueError("Digital object displayName was not returned by the API")
173
+
174
+ os.makedirs(output_path, exist_ok=True)
175
+ final_output_path = os.path.join(output_path, display_name)
176
+ else:
177
+ final_output_path = output_path
178
+
179
+ with open(final_output_path, "wb") as file_handle:
180
+ file_handle.write(file_bytes)
181
+
182
+ return final_output_path
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: das-cli
3
- Version: 1.2.33
3
+ Version: 1.3.0
4
4
  Summary: DAS api client.
5
5
  Author: Royal Netherlands Institute for Sea Research
6
6
  License-Expression: MIT
@@ -185,6 +185,16 @@ das entry update --attribute <AttributeName> [--code CODE] <file_path>
185
185
  das entry upload-digital-object --entry-code ENT001 --type Dataset --description "CTD raw" c:\data\ctd.zip
186
186
  ```
187
187
 
188
+ #### Direct download a digital object
189
+
190
+ ```bash
191
+ # Download by entry and digital object codes
192
+ das entry direct-download-digital-object --entry-code ENT001 --digital-object-code DO001 --out C:\Downloads\
193
+
194
+ # Download by IDs
195
+ das entry direct-download-digital-object --entry-id e1987f3e-7db7-11f0-a7e8-0edcca226f3d --attribute-id 126 --digital-object-id cf335b17-80e3-4151-aa80-40b69fe0567e --out C:\Downloads\file.bin
196
+ ```
197
+
188
198
  #### Link or unlink digital objects
189
199
 
190
200
  ```bash
@@ -925,6 +935,39 @@ digital_object_id = digital_objects_manager.upload_digital_object(
925
935
  )
926
936
  ```
927
937
 
938
+ #### Direct Download Digital Object
939
+
940
+ **CLI:**
941
+ ```bash
942
+ # Download by entry and digital object codes
943
+ das entry direct-download-digital-object --entry-code ENT001 --digital-object-code DO001 --out C:\Downloads\
944
+
945
+ # Download by IDs
946
+ das entry direct-download-digital-object --entry-id e1987f3e-7db7-11f0-a7e8-0edcca226f3d --attribute-id 126 --digital-object-id cf335b17-80e3-4151-aa80-40b69fe0567e --out C:\Downloads\file.bin
947
+ ```
948
+
949
+ **Manager Layer:**
950
+ ```python
951
+ from das.managers.digital_objects_manager import DigitalObjectsManager
952
+
953
+ digital_objects_manager = DigitalObjectsManager()
954
+
955
+ # Download by codes
956
+ saved_path = digital_objects_manager.direct_download_digital_object(
957
+ entry_code="ENT001",
958
+ digital_object_code="DO001",
959
+ output_path="C:\\Downloads\\"
960
+ )
961
+
962
+ # Download by IDs
963
+ saved_path = digital_objects_manager.direct_download_digital_object(
964
+ entry_id="e1987f3e-7db7-11f0-a7e8-0edcca226f3d",
965
+ attribute_id=126,
966
+ digital_object_id="cf335b17-80e3-4151-aa80-40b69fe0567e",
967
+ output_path="C:\\Downloads\\file.bin"
968
+ )
969
+ ```
970
+
928
971
  #### Link/Unlink Digital Objects
929
972
 
930
973
  **CLI:**
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "das-cli"
7
- version = "1.2.33"
7
+ version = "1.3.00"
8
8
  authors = [
9
9
  { name="Royal Netherlands Institute for Sea Research" },
10
10
  ]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes