pyPreservica 2.0.3__py3-none-any.whl → 3.3.3__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.

Potentially problematic release.


This version of pyPreservica might be problematic. Click here for more details.

@@ -9,9 +9,8 @@ licence: Apache License 2.0
9
9
 
10
10
  """
11
11
 
12
-
13
12
  import xml.etree.ElementTree
14
- from typing import Set
13
+ from typing import Set, Callable
15
14
 
16
15
  from pyPreservica.common import *
17
16
 
@@ -59,8 +58,10 @@ class RetentionPolicy:
59
58
  class RetentionAPI(AuthenticatedAPI):
60
59
 
61
60
  def __init__(self, username=None, password=None, tenant=None, server=None, use_shared_secret=False,
62
- two_fa_secret_key: str = None, protocol: str = "https"):
63
- super().__init__(username, password, tenant, server, use_shared_secret, two_fa_secret_key, protocol)
61
+ two_fa_secret_key: str = None, protocol: str = "https", request_hook: Callable = None, credentials_path: str = 'credentials.properties'):
62
+ super().__init__(username, password, tenant, server, use_shared_secret, two_fa_secret_key,
63
+ protocol, request_hook, credentials_path)
64
+
64
65
  if self.major_version < 7 and self.minor_version < 2:
65
66
  raise RuntimeError("Retention API is only available when connected to a v6.2 System")
66
67
 
@@ -76,7 +77,8 @@ class RetentionAPI(AuthenticatedAPI):
76
77
 
77
78
  """
78
79
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/xml;charset=UTF-8'}
79
- request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}', headers=headers)
80
+ request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}',
81
+ headers=headers)
80
82
  if request.status_code == requests.codes.ok:
81
83
  xml_response = str(request.content.decode('utf-8'))
82
84
  logger.debug(xml_response)
@@ -90,14 +92,22 @@ class RetentionAPI(AuthenticatedAPI):
90
92
  security_tag = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}SecurityTag').text
91
93
  rp.security_tag = security_tag
92
94
  start_date_field = entity_response.find(
93
- f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}StartDateField').text
94
- rp.start_date_field = start_date_field
95
- period = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}Period').text
96
- rp.period = period
97
- period_unit = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}PeriodUnit').text
98
- rp.period_unit = period_unit
99
- expiry_action = entity_response.find(
100
- f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}ExpiryAction')
95
+ f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}StartDateField')
96
+ if start_date_field is not None:
97
+ rp.start_date_field = start_date_field.text
98
+ else:
99
+ rp.start_date_field = None
100
+ period = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}Period')
101
+ if period is not None:
102
+ rp.period = period.text
103
+ else:
104
+ rp.period = None
105
+ period_unit = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}PeriodUnit')
106
+ if period_unit is not None:
107
+ rp.period_unit = period_unit.text
108
+ else:
109
+ rp.period_unit = None
110
+ expiry_action = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}ExpiryAction')
101
111
  if expiry_action is not None:
102
112
  rp.expiry_action = expiry_action.text
103
113
  else:
@@ -132,8 +142,9 @@ class RetentionAPI(AuthenticatedAPI):
132
142
  """
133
143
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'text/plain;charset=UTF-8'}
134
144
  data = str(status)
135
- request = self.session.put(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}/assignable',
136
- headers=headers, data=data)
145
+ request = self.session.put(
146
+ f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}/assignable',
147
+ headers=headers, data=data)
137
148
  if request.status_code == requests.codes.ok:
138
149
  pass
139
150
  elif request.status_code == requests.codes.unauthorized:
@@ -228,7 +239,8 @@ class RetentionAPI(AuthenticatedAPI):
228
239
 
229
240
  xml_request = xml.etree.ElementTree.tostring(retention_policy, encoding='utf-8')
230
241
 
231
- request = self.session.put(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}', data=xml_request,
242
+ request = self.session.put(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}',
243
+ data=xml_request,
232
244
  headers=headers)
233
245
  if request.status_code == requests.codes.ok:
234
246
  return self.policy(reference)
@@ -372,7 +384,8 @@ class RetentionAPI(AuthenticatedAPI):
372
384
  """
373
385
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/xml;charset=UTF-8'}
374
386
  data = {'start': str(0), 'max': "250"}
375
- request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies', data=data, headers=headers)
387
+ request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies', data=data,
388
+ headers=headers)
376
389
  if request.status_code == requests.codes.ok:
377
390
  xml_response = str(request.content.decode('utf-8'))
378
391
  logger.debug(xml_response)
@@ -388,10 +401,10 @@ class RetentionAPI(AuthenticatedAPI):
388
401
  else:
389
402
  raise RuntimeError(request.status_code, "policies failed")
390
403
 
391
- def policies(self) -> Set[RetentionPolicy]:
404
+ def policies(self, maximum: int = 250, next_page: str = None) -> PagedSet:
392
405
  """
393
406
  Return a list of all retention policies
394
- Only returns the first 250 policies in the system
407
+ Returns a maximum of 250 policies by default
395
408
 
396
409
 
397
410
  :return: Set of retention policies
@@ -399,22 +412,33 @@ class RetentionAPI(AuthenticatedAPI):
399
412
 
400
413
  """
401
414
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/xml;charset=UTF-8'}
402
- data = {'start': str(0), 'max': "250"}
403
- request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies', data=data, headers=headers)
415
+
416
+ if next_page is None:
417
+ params = {'start': '0', 'max': str(maximum)}
418
+ request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies', params=params,
419
+ headers=headers)
420
+ else:
421
+ request = self.session.get(next_page, headers=headers)
422
+
404
423
  if request.status_code == requests.codes.ok:
405
424
  xml_response = str(request.content.decode('utf-8'))
406
425
  entity_response = xml.etree.ElementTree.fromstring(xml_response)
407
426
  logger.debug(xml_response)
408
427
  result = set()
428
+ next_url = entity_response.find(f'.//{{{self.entity_ns}}}Paging/{{{self.entity_ns}}}Next')
409
429
  total_results = int(entity_response.find(
410
430
  f'.//{{{self.entity_ns}}}TotalResults').text)
411
- if total_results > 250:
412
- logger.error("Not all retention policies have been returned.")
413
431
  for assignment in entity_response.findall(f'.//{{{self.entity_ns}}}RetentionPolicy'):
414
432
  ref = assignment.attrib['ref']
415
433
  name = assignment.attrib['name']
416
434
  result.add(self.policy(reference=ref))
417
- return result
435
+ has_more = True
436
+ url = None
437
+ if next_url is None:
438
+ has_more = False
439
+ else:
440
+ url = next_url.text
441
+ return PagedSet(result, has_more, total_results, url)
418
442
  elif request.status_code == requests.codes.unauthorized:
419
443
  self.token = self.__token__()
420
444
  return self.policies()
@@ -453,7 +477,11 @@ class RetentionAPI(AuthenticatedAPI):
453
477
  api_id = entity_response.find(f'.//{{{self.rm_ns}}}ApiId').text
454
478
  policy_ref = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy').text
455
479
  entity_ref = entity_response.find(f'.//{{{self.rm_ns}}}Entity').text
456
- start_date = entity_response.find(f'.//{{{self.rm_ns}}}StartDate').text
480
+ start_date = entity_response.find(f'.//{{{self.rm_ns}}}StartDate')
481
+ if start_date is not None:
482
+ start_date = start_date.text
483
+ else:
484
+ start_date = None
457
485
  assert entity_ref == entity.reference
458
486
  assert policy_ref == policy.reference
459
487
  return RetentionAssignment(entity_ref, policy_ref, api_id, start_date)
@@ -514,7 +542,11 @@ class RetentionAPI(AuthenticatedAPI):
514
542
  entity_ref = assignment.find(f'.//{{{self.rm_ns}}}Entity').text
515
543
  assert entity_ref == entity.reference
516
544
  policy = assignment.find(f'.//{{{self.rm_ns}}}RetentionPolicy').text
517
- start_date = assignment.find(f'.//{{{self.rm_ns}}}StartDate').text
545
+ start_date = assignment.find(f'.//{{{self.rm_ns}}}StartDate')
546
+ if start_date is not None:
547
+ start_date = start_date.text
548
+ else:
549
+ start_date = None
518
550
  expired = bool(assignment.find(f'.//{{{self.rm_ns}}}Expired').text == 'true')
519
551
  api_id = assignment.find(f'.//{{{self.rm_ns}}}ApiId').text
520
552
  ra = RetentionAssignment(entity_ref, policy, api_id, start_date, expired)
@@ -0,0 +1,295 @@
1
+ """
2
+ pyPreservica Settings API module definition
3
+
4
+ API for retrieving information about configuration settings.
5
+
6
+ author: James Carr
7
+ licence: Apache License 2.0
8
+
9
+ """
10
+
11
+ from typing import Callable
12
+
13
+ from pyPreservica.common import *
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class SettingsAPI(AuthenticatedAPI):
19
+ """
20
+ API for retrieving information about configuration settings.
21
+
22
+ Includes methods for:
23
+
24
+ * metadata-enrichment
25
+
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ username=None,
31
+ password=None,
32
+ tenant=None,
33
+ server=None,
34
+ use_shared_secret=False,
35
+ two_fa_secret_key: str = None,
36
+ protocol: str = "https",
37
+ request_hook: Callable = None,
38
+ credentials_path: str = "credentials.properties",
39
+ ):
40
+ super().__init__(
41
+ username,
42
+ password,
43
+ tenant,
44
+ server,
45
+ use_shared_secret,
46
+ two_fa_secret_key,
47
+ protocol,
48
+ request_hook,
49
+ credentials_path,
50
+ )
51
+
52
+ if self.major_version < 7 and self.minor_version < 7:
53
+ raise RuntimeError(
54
+ "Settings API is only available when connected to a v7.7 System or higher"
55
+ )
56
+
57
+ self.base_url = "api/settings"
58
+
59
+ def metadata_enrichment_rules(self, profile_id: str = None) -> dict:
60
+ """
61
+ Returns a list of metadata enrichment rules.
62
+ An empty selection implies that the rule is applied to all content.
63
+ Rules define where particular behaviours, defined by profiles, will be applied.
64
+ Rules are evaluated in order, with the first matching rule being applied.
65
+
66
+ :param profile_id: The rules for a specific profile id, Set to None for all rules
67
+ :type profile_id: str
68
+
69
+ """
70
+ headers = {
71
+ HEADER_TOKEN: self.token,
72
+ "Accept": "application/json",
73
+ "Content-Type": "application/json;charset=UTF-8",
74
+ }
75
+
76
+ endpoint: str = "/metadata-enrichment/config/rules"
77
+
78
+ request = self.session.get(
79
+ f"{self.protocol}://{self.server}/{self.base_url}{endpoint}",
80
+ headers=headers)
81
+
82
+ if request.status_code == requests.codes.ok:
83
+ rules: dict = json.loads(request.content.decode("utf-8"))
84
+ if profile_id is None:
85
+ return rules
86
+ else:
87
+ profile_rules = []
88
+ for rule in rules["rules"]:
89
+ if rule["profileId"] == profile_id:
90
+ profile_rules.append(rule)
91
+ return {"rules": profile_rules}
92
+ else:
93
+ logger.debug(request.content.decode("utf-8"))
94
+ raise RuntimeError(request.status_code, f"metadata_enrichment_rules failed")
95
+
96
+ def metadata_enrichment_delete_rule(self, rule_id: str):
97
+ """
98
+ Deletes a metadata enrichment rule.
99
+
100
+ :param rule_id: The rule id
101
+ :type rule_id: str
102
+
103
+ :return: No return value
104
+ :rtype: None
105
+
106
+ """
107
+ headers = {
108
+ HEADER_TOKEN: self.token,
109
+ "Accept": "application/json",
110
+ "Content-Type": "application/json;charset=UTF-8",
111
+ }
112
+
113
+ endpoint: str = f"/metadata-enrichment/config/rules/{rule_id}"
114
+
115
+ request = self.session.delete(
116
+ f"{self.protocol}://{self.server}/{self.base_url}{endpoint}", headers=headers)
117
+
118
+ if request.status_code == requests.codes.no_content:
119
+ return
120
+ else:
121
+ logger.debug(request.content.decode("utf-8"))
122
+ raise RuntimeError(request.status_code, f"metadata_enrichment_delete_rule failed")
123
+
124
+ def metadata_enrichment_add_rule(self, profile_id: str, priority: int = 1):
125
+ """
126
+ Create a metadata enrichment rule to control when metadata enrichment profiles are applied and return it.
127
+ Rules define where particular behaviours, defined by profiles, will be applied.
128
+ Rules are evaluated in order, with the first matching rule being applied.
129
+ Note that not specifying, or specifying an empty selection implies that the rule will be applied to all content.
130
+ Currently only securityDescriptorSelector, representationSelector and hierarchySelector are supported selectors.
131
+ If a rule already exists for the requested priority, existing rules will be shifted down priority to accommodate the new entry.
132
+
133
+ :param profile_id: The profile id
134
+ :type profile_id: str
135
+
136
+ :param priority: The rule priority
137
+ :type priority: int
138
+
139
+ :return: The metadata enrichment rule
140
+ :rtype: dict
141
+ """
142
+
143
+ headers = {
144
+ HEADER_TOKEN: self.token,
145
+ "Accept": "application/json",
146
+ "Content-Type": "application/json;charset=UTF-8",
147
+ }
148
+
149
+ endpoint: str = "/metadata-enrichment/config/rules"
150
+
151
+ rule: dict = {
152
+ "profileId": profile_id,
153
+ "priority": str(priority),
154
+ "selectorSettings": {},
155
+ }
156
+
157
+ request = self.session.post(
158
+ f"{self.protocol}://{self.server}/{self.base_url}/{endpoint}",
159
+ headers=headers,
160
+ json=rule,
161
+ )
162
+ if request.status_code == requests.codes.created:
163
+ return json.loads(request.content.decode("utf-8"))
164
+ else:
165
+ logger.debug(request.content.decode("utf-8"))
166
+ raise RuntimeError(
167
+ request.status_code, f"metadata_enrichment_add_rule failed"
168
+ )
169
+
170
+ def metadata_enrichment_add_profile(self, name: str, active: bool = True):
171
+ """
172
+ Create a metadata enrichment profile to control automatic metadata enrichment of content and return it.
173
+ Profiles define a set of behaviours that will be applied when the profile is selected by a rule.
174
+ A profile has no effect if it is not used by a rule. Includes settings for PII identification.
175
+ PII detection tools may be run against the full text extracted from content.
176
+
177
+
178
+ :param name: The profile name
179
+ :type name: str
180
+
181
+ :param active: The profile active status
182
+ :type active: bool
183
+
184
+ :return: The metadata enrichment profile
185
+ :rtype: dict
186
+
187
+ """
188
+
189
+ headers = {
190
+ HEADER_TOKEN: self.token,
191
+ "Accept": "application/json",
192
+ "Content-Type": "application/json;charset=UTF-8",
193
+ }
194
+
195
+ endpoint: str = "/metadata-enrichment/config/profiles"
196
+
197
+ profile: dict = {"name": name, "piiSettings": {"active": str(active).lower()}}
198
+
199
+ request = self.session.post(
200
+ f"{self.protocol}://{self.server}/{self.base_url}{endpoint}",
201
+ headers=headers, json=profile)
202
+
203
+ if request.status_code == requests.codes.created:
204
+ return json.loads(request.content.decode("utf-8"))
205
+ else:
206
+ logger.debug(request.content.decode("utf-8"))
207
+ raise RuntimeError(request.status_code, f"metadata_enrichment_add_profile failed")
208
+
209
+ def metadata_enrichment_profile(self, profile_id: str) -> dict:
210
+ """
211
+ Returns a single profile by its ID
212
+ Profiles define a set of behaviours that will be applied when the profile is selected by a rule.
213
+ A profile has no effect if it is not used by a rule. Includes settings for PII identification.
214
+ PII detection tools may be run against the full text extracted from content.
215
+
216
+ :param profile_id: The profile name
217
+ :type profile_id: str
218
+
219
+ :return: The metadata enrichment profile
220
+ :rtype: dict
221
+
222
+ """
223
+ headers = {
224
+ HEADER_TOKEN: self.token,
225
+ "Accept": "application/json",
226
+ "Content-Type": "application/json;charset=UTF-8",
227
+ }
228
+
229
+ endpoint: str = f"/metadata-enrichment/config/profiles/{profile_id}"
230
+
231
+ request = self.session.get(
232
+ f"{self.protocol}://{self.server}/{self.base_url}{endpoint}", headers=headers)
233
+
234
+ if request.status_code == requests.codes.ok:
235
+ return json.loads(request.content.decode("utf-8"))
236
+ else:
237
+ logger.debug(request.content.decode("utf-8"))
238
+ raise RuntimeError(request.status_code, f"metadata_enrichment_profile failed")
239
+
240
+ def metadata_enrichment_delete_profile(self, profile_id: str) -> None:
241
+ """
242
+ Deletes a metadata enrichment profile
243
+
244
+ :param profile_id: The profile name
245
+ :type profile_id: str
246
+
247
+ :return: No return value
248
+ :rtype: None
249
+
250
+ """
251
+ headers = {
252
+ HEADER_TOKEN: self.token,
253
+ "Accept": "application/json",
254
+ "Content-Type": "application/json;charset=UTF-8",
255
+ }
256
+
257
+ endpoint: str = f"/metadata-enrichment/config/profiles/{profile_id}"
258
+
259
+ request = self.session.delete(
260
+ f"{self.protocol}://{self.server}/{self.base_url}{endpoint}", headers=headers)
261
+
262
+ if request.status_code == requests.codes.forbidden:
263
+ logger.debug(request.content.decode("utf-8"))
264
+ raise RuntimeError(request.status_code, f"Can't delete a profile with rules assigned")
265
+
266
+ if request.status_code == requests.codes.no_content:
267
+ return
268
+ else:
269
+ logger.debug(request.content.decode("utf-8"))
270
+ raise RuntimeError(request.status_code, f"metadata_enrichment_delete_profile failed")
271
+
272
+ def metadata_enrichment_profiles(self) -> dict:
273
+ """
274
+ Returns the list of all metadata enrichment profiles.
275
+ Profiles define a set of behaviours that will be applied when the profile is selected by a rule.
276
+ A profile has no effect if it is not used by a rule. Includes settings for PII identification.
277
+ PII detection tools may be run against the full text extracted from content.
278
+ """
279
+
280
+ headers = {
281
+ HEADER_TOKEN: self.token,
282
+ "Accept": "application/json",
283
+ "Content-Type": "application/json;charset=UTF-8",
284
+ }
285
+
286
+ endpoint: str = "/metadata-enrichment/config/profiles"
287
+
288
+ request = self.session.get(
289
+ f"{self.protocol}://{self.server}/{self.base_url}{endpoint}", headers=headers)
290
+
291
+ if request.status_code == requests.codes.ok:
292
+ return json.loads(request.content.decode("utf-8"))
293
+ else:
294
+ logger.debug(request.content.decode("utf-8"))
295
+ raise RuntimeError(request.status_code, f"metadata_enrichment_profiles failed")