pyPreservica 2.9.0__py3-none-any.whl → 2.9.2__py3-none-any.whl
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.
- pyPreservica/__init__.py +2 -2
- pyPreservica/common.py +3 -3
- pyPreservica/contentAPI.py +109 -1
- pyPreservica/entityAPI.py +3 -0
- pyPreservica/mdformsAPI.py +127 -0
- {pyPreservica-2.9.0.dist-info → pyPreservica-2.9.2.dist-info}/METADATA +1 -1
- {pyPreservica-2.9.0.dist-info → pyPreservica-2.9.2.dist-info}/RECORD +10 -10
- {pyPreservica-2.9.0.dist-info → pyPreservica-2.9.2.dist-info}/LICENSE.txt +0 -0
- {pyPreservica-2.9.0.dist-info → pyPreservica-2.9.2.dist-info}/WHEEL +0 -0
- {pyPreservica-2.9.0.dist-info → pyPreservica-2.9.2.dist-info}/top_level.txt +0 -0
pyPreservica/__init__.py
CHANGED
|
@@ -7,7 +7,7 @@ licence: Apache License 2.0
|
|
|
7
7
|
|
|
8
8
|
"""
|
|
9
9
|
from .common import *
|
|
10
|
-
from .contentAPI import ContentAPI
|
|
10
|
+
from .contentAPI import ContentAPI, Field, SortOrder
|
|
11
11
|
from .entityAPI import EntityAPI
|
|
12
12
|
from .uploadAPI import UploadAPI, simple_asset_package, complex_asset_package, cvs_to_xsd, cvs_to_xml, \
|
|
13
13
|
cvs_to_cmis_xslt, csv_to_search_xml, generic_asset_package, upload_config, multi_asset_package
|
|
@@ -23,6 +23,6 @@ from .mdformsAPI import MetadataGroupsAPI, Group, GroupField, GroupFieldType
|
|
|
23
23
|
__author__ = "James Carr (drjamescarr@gmail.com)"
|
|
24
24
|
|
|
25
25
|
# Version of the pyPreservica package
|
|
26
|
-
__version__ = "2.9.
|
|
26
|
+
__version__ = "2.9.2"
|
|
27
27
|
|
|
28
28
|
__license__ = "Apache License Version 2.0"
|
pyPreservica/common.py
CHANGED
|
@@ -79,9 +79,9 @@ class FileHash:
|
|
|
79
79
|
|
|
80
80
|
def identifiersToDict(identifiers: set) -> dict:
|
|
81
81
|
"""
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
Convert a set of tuples to a dict
|
|
83
|
+
:param identifiers:
|
|
84
|
+
:return:
|
|
85
85
|
"""
|
|
86
86
|
result = {}
|
|
87
87
|
for identifier_tuple in identifiers:
|
pyPreservica/contentAPI.py
CHANGED
|
@@ -10,11 +10,28 @@ licence: Apache License 2.0
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import csv
|
|
13
|
-
from typing import Generator, Callable
|
|
13
|
+
from typing import Generator, Callable, Optional
|
|
14
14
|
from pyPreservica.common import *
|
|
15
15
|
|
|
16
16
|
logger = logging.getLogger(__name__)
|
|
17
17
|
|
|
18
|
+
class SortOrder(Enum):
|
|
19
|
+
asc = 1
|
|
20
|
+
desc = 2
|
|
21
|
+
|
|
22
|
+
class Field:
|
|
23
|
+
name: str
|
|
24
|
+
value: Optional[str]
|
|
25
|
+
operator: Optional[str]
|
|
26
|
+
sort_order: Optional[SortOrder]
|
|
27
|
+
|
|
28
|
+
def __init__(self, name: str, value: str, operator: Optional[str]=None, sort_order: Optional[SortOrder]=None):
|
|
29
|
+
self.name = name
|
|
30
|
+
self.value = value
|
|
31
|
+
self.operator = operator
|
|
32
|
+
self.sort_order = sort_order
|
|
33
|
+
|
|
34
|
+
|
|
18
35
|
|
|
19
36
|
class ContentAPI(AuthenticatedAPI):
|
|
20
37
|
|
|
@@ -212,6 +229,97 @@ class ContentAPI(AuthenticatedAPI):
|
|
|
212
229
|
writer.writeheader()
|
|
213
230
|
writer.writerows(self.search_index_filter_list(query, page_size, filter_values, sort_values))
|
|
214
231
|
|
|
232
|
+
def search_fields(self, query: str = "%", fields: list[Field]=None, page_size: int = 25) -> Generator:
|
|
233
|
+
"""
|
|
234
|
+
Run a search query with multiple fields
|
|
235
|
+
|
|
236
|
+
:param query: The main search query.
|
|
237
|
+
:param fields: List of search fields
|
|
238
|
+
:param page_size: The default search page size
|
|
239
|
+
:return: search result
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
if self.major_version < 7 and self.minor_version < 5:
|
|
243
|
+
raise RuntimeError("search_fields API call is not available when connected to a v7.5 System")
|
|
244
|
+
|
|
245
|
+
search_result = self._search_fields(query=query, fields=fields, start_index=0, page_size=page_size)
|
|
246
|
+
for e in search_result.results_list:
|
|
247
|
+
yield e
|
|
248
|
+
found = len(search_result.results_list)
|
|
249
|
+
while search_result.hits > found:
|
|
250
|
+
search_result = self._search_fields(query=query, fields=fields, start_index=found, page_size=page_size)
|
|
251
|
+
for e in search_result.results_list:
|
|
252
|
+
yield e
|
|
253
|
+
found = found + len(search_result.results_list)
|
|
254
|
+
|
|
255
|
+
def _search_fields(self, query: str = "%", fields: list[Field]=None, start_index: int = 0, page_size: int = 25):
|
|
256
|
+
|
|
257
|
+
start_from = str(start_index)
|
|
258
|
+
headers = {'Content-Type': 'application/x-www-form-urlencoded', HEADER_TOKEN: self.token}
|
|
259
|
+
|
|
260
|
+
if fields is None:
|
|
261
|
+
fields = []
|
|
262
|
+
|
|
263
|
+
field_list = []
|
|
264
|
+
sort_list = []
|
|
265
|
+
metadata_elements = []
|
|
266
|
+
for field in fields:
|
|
267
|
+
metadata_elements.append(field.name)
|
|
268
|
+
if field.value is None or field.value == "":
|
|
269
|
+
field_list.append('{' f' "name": "{field.name}", "values": [] ' + '}')
|
|
270
|
+
elif field.operator == "NOT":
|
|
271
|
+
field_list.append('{' f' "name": "{field.name}", "values": ["{field.value}"], "operator": "NOT" ' + '}')
|
|
272
|
+
else:
|
|
273
|
+
field_list.append('{' f' "name": "{field.name}", "values": ["{field.value}"] ' + '}')
|
|
274
|
+
|
|
275
|
+
if field.sort_order is not None:
|
|
276
|
+
sort_list.append(f'{{"sortFields": ["{field.name}"], "sortOrder": "{field.sort_order.name}"}}')
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
filter_terms = ','.join(field_list)
|
|
280
|
+
|
|
281
|
+
if len(sort_list) == 0:
|
|
282
|
+
query_term = ('{ "q": "%s", "fields": [ %s ] }' % (query, filter_terms))
|
|
283
|
+
else:
|
|
284
|
+
sort_terms = ','.join(sort_list)
|
|
285
|
+
query_term = ('{ "q": "%s", "fields": [ %s ], "sort": [ %s ]}' % (query, filter_terms, sort_terms))
|
|
286
|
+
|
|
287
|
+
if len(metadata_elements) == 0:
|
|
288
|
+
metadata_elements.append("xip.title")
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
payload = {'start': start_from, 'max': str(page_size), 'metadata': list(metadata_elements), 'q': query_term}
|
|
292
|
+
logger.debug(payload)
|
|
293
|
+
results = self.session.post(f'{self.protocol}://{self.server}/api/content/search', data=payload,
|
|
294
|
+
headers=headers)
|
|
295
|
+
results_list = []
|
|
296
|
+
if results.status_code == requests.codes.ok:
|
|
297
|
+
json_doc = results.json()
|
|
298
|
+
metadata = json_doc['value']['metadata']
|
|
299
|
+
refs = list(json_doc['value']['objectIds'])
|
|
300
|
+
refs = list(map(lambda x: content_api_identifier_to_type(x), refs))
|
|
301
|
+
hits = int(json_doc['value']['totalHits'])
|
|
302
|
+
|
|
303
|
+
for m_row, r_row in zip(metadata, refs):
|
|
304
|
+
results_map = {'xip.reference': r_row[1]}
|
|
305
|
+
for li in m_row:
|
|
306
|
+
results_map[li['name']] = li['value']
|
|
307
|
+
results_list.append(results_map)
|
|
308
|
+
next_start = start_index + page_size
|
|
309
|
+
|
|
310
|
+
if self.callback is not None:
|
|
311
|
+
value = str(f'{len(results_list) + start_index}:{hits}')
|
|
312
|
+
self.callback(value)
|
|
313
|
+
|
|
314
|
+
search_results = self.SearchResult(metadata, refs, hits, results_list, next_start)
|
|
315
|
+
return search_results
|
|
316
|
+
elif results.status_code == requests.codes.unauthorized:
|
|
317
|
+
self.token = self.__token__()
|
|
318
|
+
return self._search_predicates(query, predicates, start_index, page_size)
|
|
319
|
+
else:
|
|
320
|
+
logger.error(f"search failed with error code: {results.status_code}")
|
|
321
|
+
raise RuntimeError(results.status_code, f"search_index_filter failed")
|
|
322
|
+
|
|
215
323
|
def search_index_filter_list(self, query: str = "%", page_size: int = 25, filter_values: dict = None,
|
|
216
324
|
sort_values: dict = None) -> Generator:
|
|
217
325
|
"""
|
pyPreservica/entityAPI.py
CHANGED
|
@@ -454,6 +454,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
454
454
|
logger.error(request)
|
|
455
455
|
raise RuntimeError(request.status_code, "delete_identifier failed")
|
|
456
456
|
|
|
457
|
+
|
|
457
458
|
def identifiers_for_entity(self, entity: Entity) -> set[Tuple]:
|
|
458
459
|
"""
|
|
459
460
|
Get all external identifiers on an entity
|
|
@@ -491,6 +492,8 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
491
492
|
logger.error(exception)
|
|
492
493
|
raise exception
|
|
493
494
|
|
|
495
|
+
|
|
496
|
+
|
|
494
497
|
def identifier(self, identifier_type: str, identifier_value: str) -> set[Entity]:
|
|
495
498
|
"""
|
|
496
499
|
Get all entities which have the external identifier
|
pyPreservica/mdformsAPI.py
CHANGED
|
@@ -8,6 +8,7 @@ author: James Carr
|
|
|
8
8
|
licence: Apache License 2.0
|
|
9
9
|
|
|
10
10
|
"""
|
|
11
|
+
import json
|
|
11
12
|
import xml.etree.ElementTree
|
|
12
13
|
from typing import Callable, List, Union, Generator
|
|
13
14
|
|
|
@@ -247,6 +248,75 @@ class MetadataGroupsAPI(AuthenticatedAPI):
|
|
|
247
248
|
json_response: dict = self.add_group_json(json_document)
|
|
248
249
|
return json_response
|
|
249
250
|
|
|
251
|
+
def add_form(self, json_form: Union[dict, str]):
|
|
252
|
+
"""
|
|
253
|
+
Create a new Metadata fORM using a JSON dictionary object or document
|
|
254
|
+
|
|
255
|
+
:param json_form: JSON dictionary or string
|
|
256
|
+
:type json_form: dict
|
|
257
|
+
|
|
258
|
+
:return: JSON document
|
|
259
|
+
:rtype: dict
|
|
260
|
+
|
|
261
|
+
"""
|
|
262
|
+
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
|
|
263
|
+
url = f'{self.protocol}://{self.server}/api/metadata/forms/'
|
|
264
|
+
|
|
265
|
+
if isinstance(json_form, dict):
|
|
266
|
+
with self.session.post(url, headers=headers, json=json_form) as request:
|
|
267
|
+
if request.status_code == requests.codes.unauthorized:
|
|
268
|
+
self.token = self.__token__()
|
|
269
|
+
return self.add_form_json(json_form)
|
|
270
|
+
elif request.status_code == requests.codes.created:
|
|
271
|
+
return json.loads(str(request.content.decode('utf-8')))
|
|
272
|
+
else:
|
|
273
|
+
exception = HTTPException(None, request.status_code, request.url, "add_form_json",
|
|
274
|
+
request.content.decode('utf-8'))
|
|
275
|
+
logger.error(exception)
|
|
276
|
+
raise exception
|
|
277
|
+
|
|
278
|
+
elif isinstance(json_form, str):
|
|
279
|
+
with self.session.post(url, headers=headers, data=json_form) as request:
|
|
280
|
+
if request.status_code == requests.codes.unauthorized:
|
|
281
|
+
self.token = self.__token__()
|
|
282
|
+
return self.add_form_json(json_form)
|
|
283
|
+
elif request.status_code == requests.codes.created:
|
|
284
|
+
return json.loads(str(request.content.decode('utf-8')))
|
|
285
|
+
else:
|
|
286
|
+
exception = HTTPException(None, request.status_code, request.url, "add_form_json",
|
|
287
|
+
request.content.decode('utf-8'))
|
|
288
|
+
logger.error(exception)
|
|
289
|
+
raise exception
|
|
290
|
+
else:
|
|
291
|
+
raise RuntimeError("Argument must be a JSON dictionary or a JSON str")
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
# def set_default_form(self, form_id: str):
|
|
295
|
+
# """
|
|
296
|
+
# Set the default form
|
|
297
|
+
#
|
|
298
|
+
# """
|
|
299
|
+
#
|
|
300
|
+
# headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
|
|
301
|
+
# url = f'{self.protocol}://{self.server}/api/metadata/forms/{form_id}/default'
|
|
302
|
+
#
|
|
303
|
+
# payload: dict = {"default": True, "useAsDefault": True}
|
|
304
|
+
#
|
|
305
|
+
# with self.session.get(url, headers=headers, json=json.dumps(payload)) as request:
|
|
306
|
+
# if request.status_code == requests.codes.unauthorized:
|
|
307
|
+
# self.token = self.__token__()
|
|
308
|
+
# return self.set_default_form(form_id)
|
|
309
|
+
# elif request.status_code == requests.codes.ok:
|
|
310
|
+
# return json.loads(str(request.content.decode('utf-8')))
|
|
311
|
+
# else:
|
|
312
|
+
# exception = HTTPException(None, request.status_code, request.url, "set_default_form",
|
|
313
|
+
# request.content.decode('utf-8'))
|
|
314
|
+
# logger.error(exception)
|
|
315
|
+
# raise exception
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
250
320
|
def add_group_json(self, json_object: Union[dict, str]) -> dict:
|
|
251
321
|
"""
|
|
252
322
|
Create a new Metadata Group using a JSON dictionary object or document
|
|
@@ -351,6 +421,63 @@ class MetadataGroupsAPI(AuthenticatedAPI):
|
|
|
351
421
|
logger.error(exception)
|
|
352
422
|
raise exception
|
|
353
423
|
|
|
424
|
+
def forms(self, schema_uri: str|None = None) -> dict:
|
|
425
|
+
"""
|
|
426
|
+
Return all the metadata Forms in the tenancy as a list of JSON dict objects
|
|
427
|
+
|
|
428
|
+
:param schema_uri: The Form schema Uri
|
|
429
|
+
:type schema_uri: str
|
|
430
|
+
|
|
431
|
+
:return: List of JSON dictionary object
|
|
432
|
+
:rtype: dict
|
|
433
|
+
|
|
434
|
+
"""
|
|
435
|
+
|
|
436
|
+
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
|
|
437
|
+
url = f'{self.protocol}://{self.server}/api/metadata/forms'
|
|
438
|
+
params = {}
|
|
439
|
+
if schema_uri is not None:
|
|
440
|
+
params = {'schemaUri': schema_uri}
|
|
441
|
+
with self.session.get(url, headers=headers, params=params) as request:
|
|
442
|
+
if request.status_code == requests.codes.unauthorized:
|
|
443
|
+
self.token = self.__token__()
|
|
444
|
+
return self.forms_json()
|
|
445
|
+
elif request.status_code == requests.codes.ok:
|
|
446
|
+
return json.loads(str(request.content.decode('utf-8')))['metadataForms']
|
|
447
|
+
else:
|
|
448
|
+
exception = HTTPException(None, request.status_code, request.url, "forms_json",
|
|
449
|
+
request.content.decode('utf-8'))
|
|
450
|
+
logger.error(exception)
|
|
451
|
+
raise exception
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def form(self, form_id: str) -> dict:
|
|
455
|
+
"""
|
|
456
|
+
Return a Form as a JSON dict object
|
|
457
|
+
|
|
458
|
+
:param form_id: The Form id
|
|
459
|
+
:type form_id: str
|
|
460
|
+
|
|
461
|
+
:return: JSON document
|
|
462
|
+
:rtype: dict
|
|
463
|
+
|
|
464
|
+
"""
|
|
465
|
+
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
|
|
466
|
+
url = f'{self.protocol}://{self.server}/api/metadata/forms/{form_id}'
|
|
467
|
+
with self.session.get(url, headers=headers) as request:
|
|
468
|
+
if request.status_code == requests.codes.unauthorized:
|
|
469
|
+
self.token = self.__token__()
|
|
470
|
+
return self.form_json(form_id)
|
|
471
|
+
elif request.status_code == requests.codes.ok:
|
|
472
|
+
return json.loads(str(request.content.decode('utf-8')))
|
|
473
|
+
else:
|
|
474
|
+
exception = HTTPException(None, request.status_code, request.url, "form_json",
|
|
475
|
+
request.content.decode('utf-8'))
|
|
476
|
+
logger.error(exception)
|
|
477
|
+
raise exception
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
|
|
354
481
|
def groups(self) -> Generator[Group, None, None]:
|
|
355
482
|
"""
|
|
356
483
|
Return all the metadata Groups in the tenancy as Group Objects
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
pyPreservica/__init__.py,sha256=
|
|
1
|
+
pyPreservica/__init__.py,sha256=hzcuWdS8XXKexRdqvojfv-pqrW_vS9bF5Hh3Th3HkcY,1177
|
|
2
2
|
pyPreservica/adminAPI.py,sha256=511bc5KtrCAXbDyBk39dmDnxUVDaOu6xaiyu0jYhxa4,37781
|
|
3
3
|
pyPreservica/authorityAPI.py,sha256=Eule8g6LXr8c8SFcJgpRah4lH1FgevUItO5HhHDEaZE,9172
|
|
4
|
-
pyPreservica/common.py,sha256=
|
|
5
|
-
pyPreservica/contentAPI.py,sha256=
|
|
6
|
-
pyPreservica/entityAPI.py,sha256=
|
|
7
|
-
pyPreservica/mdformsAPI.py,sha256=
|
|
4
|
+
pyPreservica/common.py,sha256=qVmH5xazlxX02pZaYAX1GT-k0fDuzF8JmEIrYBGiTtw,37648
|
|
5
|
+
pyPreservica/contentAPI.py,sha256=6L7z5KZZDuBBLTm9GQ9RLOhugAawPnuQIgv1NZf0vIU,22060
|
|
6
|
+
pyPreservica/entityAPI.py,sha256=BxrJ-irL0-ohZGVd5uduvFgDgMvrB3Xf2pzTaZ00-Cg,118999
|
|
7
|
+
pyPreservica/mdformsAPI.py,sha256=8atJKNi9mGoQR9DSaEJSIdVBEwBstAuktSPUiJczU3w,19128
|
|
8
8
|
pyPreservica/monitorAPI.py,sha256=HD-PUPdSI9wGAa07e2_2_-FLINH8PoWUwpFogz7F-j4,6269
|
|
9
9
|
pyPreservica/opex.py,sha256=ccra1S4ojUXS3PlbU8WfxajOkJrwG4OykBnNrYP_jus,4875
|
|
10
10
|
pyPreservica/parAPI.py,sha256=bgaQvYfWNnzdD7ibKMV3ZV85pNkEdSoLsgVigoiFFfw,10771
|
|
@@ -12,8 +12,8 @@ pyPreservica/retentionAPI.py,sha256=31yKHbatxj9kt5vbqyTeg98nrMotd2iL4jsiNhcOLg4,
|
|
|
12
12
|
pyPreservica/uploadAPI.py,sha256=3XV3_i7mwp0IPcnx1sW4U01rkphtAzq5Se3G_l28wIM,96469
|
|
13
13
|
pyPreservica/webHooksAPI.py,sha256=_K3KUOsmwYf8qMa-mD47sAmNUW7Pzb9oKVpS0VoSbC0,6827
|
|
14
14
|
pyPreservica/workflowAPI.py,sha256=wDDR5_CsJ3dhX79E5mJaziAtgYb830J0ZpNJppzgvqk,17493
|
|
15
|
-
pyPreservica-2.9.
|
|
16
|
-
pyPreservica-2.9.
|
|
17
|
-
pyPreservica-2.9.
|
|
18
|
-
pyPreservica-2.9.
|
|
19
|
-
pyPreservica-2.9.
|
|
15
|
+
pyPreservica-2.9.2.dist-info/LICENSE.txt,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
16
|
+
pyPreservica-2.9.2.dist-info/METADATA,sha256=pwbevSahu7N-Au96h32Qk_U-8Oyf2qNo66mZLh0dmlM,2779
|
|
17
|
+
pyPreservica-2.9.2.dist-info/WHEEL,sha256=YiKiUUeZQGmGJoR_0N1Y933DOBowq4AIvDe2-UIy8E4,91
|
|
18
|
+
pyPreservica-2.9.2.dist-info/top_level.txt,sha256=iIBh6NAznYQHOV8mv_y_kGKSDITek9rANyFDwJsbU-c,13
|
|
19
|
+
pyPreservica-2.9.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|