pyxecm 1.6__py3-none-any.whl → 2.0.0__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 pyxecm might be problematic. Click here for more details.

Files changed (56) hide show
  1. pyxecm/__init__.py +6 -4
  2. pyxecm/avts.py +673 -246
  3. pyxecm/coreshare.py +686 -467
  4. pyxecm/customizer/__init__.py +16 -4
  5. pyxecm/customizer/__main__.py +58 -0
  6. pyxecm/customizer/api/__init__.py +5 -0
  7. pyxecm/customizer/api/__main__.py +6 -0
  8. pyxecm/customizer/api/app.py +914 -0
  9. pyxecm/customizer/api/auth.py +154 -0
  10. pyxecm/customizer/api/metrics.py +92 -0
  11. pyxecm/customizer/api/models.py +13 -0
  12. pyxecm/customizer/api/payload_list.py +865 -0
  13. pyxecm/customizer/api/settings.py +103 -0
  14. pyxecm/customizer/browser_automation.py +332 -139
  15. pyxecm/customizer/customizer.py +1007 -1130
  16. pyxecm/customizer/exceptions.py +35 -0
  17. pyxecm/customizer/guidewire.py +322 -0
  18. pyxecm/customizer/k8s.py +713 -378
  19. pyxecm/customizer/log.py +107 -0
  20. pyxecm/customizer/m365.py +2867 -909
  21. pyxecm/customizer/nhc.py +1169 -0
  22. pyxecm/customizer/openapi.py +258 -0
  23. pyxecm/customizer/payload.py +16817 -7467
  24. pyxecm/customizer/pht.py +699 -285
  25. pyxecm/customizer/salesforce.py +516 -342
  26. pyxecm/customizer/sap.py +58 -41
  27. pyxecm/customizer/servicenow.py +593 -371
  28. pyxecm/customizer/settings.py +442 -0
  29. pyxecm/customizer/successfactors.py +408 -346
  30. pyxecm/customizer/translate.py +83 -48
  31. pyxecm/helper/__init__.py +5 -2
  32. pyxecm/helper/assoc.py +83 -43
  33. pyxecm/helper/data.py +2406 -870
  34. pyxecm/helper/logadapter.py +27 -0
  35. pyxecm/helper/web.py +229 -101
  36. pyxecm/helper/xml.py +527 -171
  37. pyxecm/maintenance_page/__init__.py +5 -0
  38. pyxecm/maintenance_page/__main__.py +6 -0
  39. pyxecm/maintenance_page/app.py +51 -0
  40. pyxecm/maintenance_page/settings.py +28 -0
  41. pyxecm/maintenance_page/static/favicon.avif +0 -0
  42. pyxecm/maintenance_page/templates/maintenance.html +165 -0
  43. pyxecm/otac.py +234 -140
  44. pyxecm/otawp.py +1436 -557
  45. pyxecm/otcs.py +7716 -3161
  46. pyxecm/otds.py +2150 -919
  47. pyxecm/otiv.py +36 -21
  48. pyxecm/otmm.py +1272 -325
  49. pyxecm/otpd.py +231 -127
  50. pyxecm-2.0.0.dist-info/METADATA +145 -0
  51. pyxecm-2.0.0.dist-info/RECORD +54 -0
  52. {pyxecm-1.6.dist-info → pyxecm-2.0.0.dist-info}/WHEEL +1 -1
  53. pyxecm-1.6.dist-info/METADATA +0 -53
  54. pyxecm-1.6.dist-info/RECORD +0 -32
  55. {pyxecm-1.6.dist-info → pyxecm-2.0.0.dist-info/licenses}/LICENSE +0 -0
  56. {pyxecm-1.6.dist-info → pyxecm-2.0.0.dist-info}/top_level.txt +0 -0
pyxecm/otac.py CHANGED
@@ -1,58 +1,57 @@
1
- """
2
- OTAC Module to implement functions to apply Archive Center settings
3
-
4
- Class: OTAC
5
- Methods:
6
-
7
- __init__ : class initializer
8
- config : returns config data set
9
- hostname: returns the Archive Center hostname
10
- set_hostname: sets the Archive Center hostname
11
- credentials: Get credentials (username + password)
12
- set_credentials: Set the credentials for Archive Center for the "ds" and "admin" users
13
- base_url: Returns the Archive Center base URL
14
- exec_url: Returns the Archive Center URL to execute commands
15
- request_form_header: Deliver the FORM request header used for the SOAP calls.
16
- request_json_header: Deliver the JSON request header used for the CRUD REST API calls.
17
- parse_request_response: Converts the text property of a request response object to a
18
- Python dict in a safe way that also handles exceptions.
19
- authenticate: Authenticates at Archive Center and retrieve Ticket
20
- authenticate_soap: Authenticate via SOAP with admin User
21
- exec_command: exec a command on Archive Center
22
- put_cert: put Certificate on Archive Center
23
- enable_cert: enables Certitificate on Archive Center via SOAP
24
- enable_certificate: Enable a certificate via the new REST API
25
- (replacing the old SOAP interface)
26
- """
1
+ """OTAC Module to implement functions to apply Archive Center settings."""
27
2
 
28
3
  __author__ = "Dr. Marc Diefenbruch"
29
- __copyright__ = "Copyright 2024, OpenText"
4
+ __copyright__ = "Copyright (C) 2024-2025, OpenText"
30
5
  __credits__ = ["Kai-Philip Gatzweiler"]
31
6
  __maintainer__ = "Dr. Marc Diefenbruch"
32
7
  __email__ = "mdiefenb@opentext.com"
33
8
 
34
- import logging
35
- import os
36
9
  import base64
37
10
  import json
38
- import requests
11
+ import logging
12
+ import os
13
+ import platform
14
+ import sys
15
+ from importlib.metadata import version
39
16
 
40
- from suds.client import Client
17
+ import requests
41
18
  from suds import WebFault
19
+ from suds.client import Client
20
+
21
+ APP_NAME = "pyxecm"
22
+ APP_VERSION = version("pyxecm")
23
+ MODULE_NAME = APP_NAME + ".otac"
42
24
 
43
- logger = logging.getLogger("pyxecm.otac")
25
+ PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
26
+ OS_INFO = f"{platform.system()} {platform.release()}"
27
+ ARCH_INFO = platform.machine()
28
+ REQUESTS_VERSION = requests.__version__
44
29
 
45
- REQUEST_FORM_HEADERS = {"Content-Type": "application/x-www-form-urlencoded"}
30
+ USER_AGENT = (
31
+ f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
32
+ f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
33
+ )
34
+
35
+ REQUEST_FORM_HEADERS = {
36
+ "User-Agent": USER_AGENT,
37
+ "Content-Type": "application/x-www-form-urlencoded",
38
+ }
46
39
 
47
40
  REQUEST_JSON_HEADERS = {
41
+ "User-Agent": USER_AGENT,
48
42
  "accept": "application/json;charset=utf-8",
49
43
  "Content-Type": "application/json",
50
44
  }
51
45
 
52
46
  REQUEST_TIMEOUT = 60
53
47
 
48
+ default_logger = logging.getLogger(MODULE_NAME)
49
+
50
+
54
51
  class OTAC:
55
- """Used to automate stettings in OpenText Archive Center."""
52
+ """Class OTAC is used to automate stettings in OpenText Archive Center."""
53
+
54
+ logger: logging.Logger = default_logger
56
55
 
57
56
  _config = None
58
57
  _soap_token: str = ""
@@ -68,19 +67,37 @@ class OTAC:
68
67
  admin_username: str,
69
68
  admin_password: str,
70
69
  otds_ticket: str | None = None,
71
- ):
72
- """Initialize the OTAC object
70
+ logger: logging.Logger = default_logger,
71
+ ) -> None:
72
+ """Initialize the OTAC object.
73
73
 
74
74
  Args:
75
- protocol (str): Either http or https.
76
- hostname (str): The hostname of the Archive Center to communicate with.
77
- port (int): The port number used to talk to the Archive Center .
78
- ds_username (str): The admin user name of Archive Center (dsadmin).
79
- ds_password (str): The admin password of Archive Center (dsadmin).
80
- admin_username (str): The admin user name of Archive Center (otadmin@otds.admin).
81
- admin_password (str): The admin password of Archive Center (otadmin@otds.admin).
75
+ protocol (str):
76
+ Either http or https.
77
+ hostname (str):
78
+ The hostname of the Archive Center to communicate with.
79
+ port (int):
80
+ The port number used to talk to the Archive Center .
81
+ ds_username (str):
82
+ The admin user name of Archive Center (dsadmin).
83
+ ds_password (str):
84
+ The admin password of Archive Center (dsadmin).
85
+ admin_username (str):
86
+ The admin user name of Archive Center (otadmin@otds.admin).
87
+ admin_password (str):
88
+ The admin password of Archive Center (otadmin@otds.admin).
89
+ otds_ticket (str, optional):
90
+ Existing OTDS authentication ticket.
91
+ logger (logging.Logger, optional):
92
+ The logging object to use for all log messages. Defaults to default_logger.
93
+
82
94
  """
83
95
 
96
+ if logger != default_logger:
97
+ self.logger = logger.getChild("otac")
98
+ for logfilter in logger.filters:
99
+ self.logger.addFilter(logfilter)
100
+
84
101
  otac_config = {}
85
102
 
86
103
  if hostname:
@@ -132,47 +149,58 @@ class OTAC:
132
149
  self._otac_ticket = otds_ticket
133
150
 
134
151
  def config(self) -> dict:
135
- """Returns the configuration dictionary
152
+ """Return the configuration dictionary.
136
153
 
137
154
  Returns:
138
155
  dict: Configuration dictionary
156
+
139
157
  """
140
158
  return self._config
141
159
 
142
160
  def hostname(self) -> str:
143
- """Returns the Archive Center hostname
161
+ """Return the Archive Center hostname.
144
162
 
145
163
  Returns:
146
164
  str: Archive Center hostname
165
+
147
166
  """
148
167
  return self.config()["hostname"]
149
168
 
150
- def set_hostname(self, hostname: str):
151
- """Sets the Archive Center hostname
169
+ # end method definition
170
+
171
+ def set_hostname(self, hostname: str) -> None:
172
+ """Set the Archive Center hostname.
152
173
 
153
174
  Args:
154
- hostname (str): new Archive Center hostname
175
+ hostname (str):
176
+ The new Archive Center hostname.
177
+
155
178
  """
156
179
  self.config()["hostname"] = hostname
157
180
 
181
+ # end method definition
182
+
158
183
  def credentials(self) -> dict:
159
- """Get credentials (username + password)
184
+ """Get credentials (username + password).
160
185
 
161
186
  Returns:
162
187
  dict: dictionary with username and password
188
+
163
189
  """
164
190
  return {
165
191
  "username": self.config()["admin_username"],
166
192
  "password": self.config()["admin_password"],
167
193
  }
168
194
 
195
+ # end method definition
196
+
169
197
  def set_credentials(
170
198
  self,
171
199
  ds_username: str = "",
172
200
  ds_password: str = "",
173
201
  admin_username: str = "",
174
202
  admin_password: str = "",
175
- ):
203
+ ) -> None:
176
204
  """Set the credentials for Archive Center for the "ds" and "admin" users.
177
205
 
178
206
  Args:
@@ -180,6 +208,7 @@ class OTAC:
180
208
  ds_password (str, optional): non-default password of the "ds" user. Defaults to "".
181
209
  admin_username (str, optional): non-default user name of the "admin" user. Defaults to "".
182
210
  admin_password (str, optional): non-default password of the "admin" user. Defaults to "".
211
+
183
212
  """
184
213
  if ds_username:
185
214
  self.config()["ds_username"] = ds_username
@@ -201,30 +230,43 @@ class OTAC:
201
230
  else:
202
231
  self.config()["admin_password"] = ""
203
232
 
233
+ # end method definition
234
+
204
235
  def base_url(self) -> str:
205
- """Returns the Archive Center base URL
236
+ """Return the Archive Center base URL.
206
237
 
207
238
  Returns:
208
239
  str: Archive Center base URL
240
+
209
241
  """
242
+
210
243
  return self.config()["baseUrl"]
211
244
 
245
+ # end method definition
246
+
212
247
  def exec_url(self) -> str:
213
- """Returns the Archive Center URL to execute commands
248
+ """Return the Archive Center URL to execute commands.
214
249
 
215
250
  Returns:
216
251
  str: Archive Center exec URL
252
+
217
253
  """
218
254
  return self.config()["execUrl"]
219
255
 
256
+ # end method definition
257
+
220
258
  def request_form_header(self) -> dict:
221
259
  """Deliver the FORM request header used for the SOAP calls.
222
- Consists of Token + Form Headers (see global variable)
260
+
261
+ Consists of Token + Form Headers (see global variable)
223
262
 
224
263
  Args:
225
264
  None.
265
+
226
266
  Return:
227
- dict: request header values
267
+ dict:
268
+ The request header for forms content type that includes the authorization token.
269
+
228
270
  """
229
271
 
230
272
  # create union of two dicts: cookie and headers
@@ -239,12 +281,16 @@ class OTAC:
239
281
 
240
282
  def request_json_header(self) -> dict:
241
283
  """Deliver the JSON request header used for the CRUD REST API calls.
242
- Consists of Cookie + JSON Headers (see global variable)
284
+
285
+ Consists of Cookie + JSON Headers (see global variable)
243
286
 
244
287
  Args:
245
288
  None.
289
+
246
290
  Return:
247
- dict: request header values
291
+ dict:
292
+ The request header for JSON content type that includes the authorization token.
293
+
248
294
  """
249
295
 
250
296
  if not self._otac_ticket:
@@ -253,7 +299,8 @@ class OTAC:
253
299
  # create union of two dicts: cookie and headers
254
300
  # (with Python 3.9 this would be easier with the "|" operator)
255
301
  request_header = {}
256
- request_header["Authorization"] = "token " + self._otac_ticket
302
+ if self._otac_ticket:
303
+ request_header["Authorization"] = "token " + self._otac_ticket
257
304
  request_header.update(REQUEST_JSON_HEADERS)
258
305
 
259
306
  return request_header
@@ -266,15 +313,22 @@ class OTAC:
266
313
  additional_error_message: str = "",
267
314
  show_error: bool = True,
268
315
  ) -> dict | None:
269
- """Converts the text property of a request response object to a
270
- Python dict in a safe way that also handles exceptions.
316
+ """Convert the text property of a request response object to a dictionary.
317
+
318
+ This is done in a safe way that also handles exceptions.
319
+
271
320
  Args:
272
- response_object (object): this is reponse object delivered by the request call
273
- additional_error_message (str): print a custom error message
274
- show_error (bool): if True log an error, if False log a warning
321
+ response_object (object):
322
+ The reponse object delivered by the request call.
323
+ additional_error_message (str):
324
+ To print a custom error message.
325
+ show_error (bool):
326
+ If True, log an error, if False log a warning.
275
327
 
276
328
  Returns:
277
- dict: response or None in case of an error
329
+ dict:
330
+ The response or None in case of an error.
331
+
278
332
  """
279
333
 
280
334
  if not response_object:
@@ -285,16 +339,17 @@ class OTAC:
285
339
  except json.JSONDecodeError as exception:
286
340
  if additional_error_message:
287
341
  message = "Cannot decode response as JSon. {}; error -> {}".format(
288
- additional_error_message, exception
342
+ additional_error_message,
343
+ exception,
289
344
  )
290
345
  else:
291
346
  message = "Cannot decode response as JSon; error -> {}".format(
292
- exception
347
+ exception,
293
348
  )
294
349
  if show_error:
295
- logger.error(message)
350
+ self.logger.error(message)
296
351
  else:
297
- logger.debug(message)
352
+ self.logger.debug(message)
298
353
  return None
299
354
  else:
300
355
  return dict_object
@@ -302,21 +357,25 @@ class OTAC:
302
357
  # end method definition
303
358
 
304
359
  def authenticate(self, revalidate: bool = False) -> dict | None:
305
- """Authenticates at Archive Center and retrieve Ticket.
360
+ """Authenticate at Archive Center and retrieve Ticket.
306
361
 
307
362
  Args:
308
- revalidate (bool, optional): determinse if a re-athentication is enforced
309
- (e.g. if session has timed out with 401 error)
310
- By default we use the OTDS ticket (if exists) for the authentication with OTCS.
311
- This switch allows the forced usage of username / password for the authentication.
363
+ revalidate (bool, optional):
364
+ Determins if a re-athentication is enforced
365
+ (e.g. if session has timed out with 401 error).
366
+ By default we use the OTDS ticket (if exists) for the authentication with OTCS.
367
+ This switch allows the forced usage of username / password for the authentication.
368
+
312
369
  Returns:
313
- dict: Cookie information of None in case of an error.
314
- Also stores cookie information in self._cookie
370
+ dict | None:
371
+ Cookie information of None in case of an error.
372
+ Also stores cookie information in self._cookie
373
+
315
374
  """
316
375
 
317
376
  # Already authenticated and session still valid?
318
377
  if self._otac_ticket and not revalidate:
319
- logger.debug(
378
+ self.logger.debug(
320
379
  "Session still valid - return existing ticket -> %s",
321
380
  str(self._otac_ticket),
322
381
  )
@@ -327,7 +386,7 @@ class OTAC:
327
386
  request_url = self.config()["authenticationUrl"]
328
387
  # Check if previous authentication was not successful.
329
388
  # Then we do the normal username + password authentication:
330
- logger.debug(
389
+ self.logger.debug(
331
390
  "Requesting OTAC ticket with User/Password; calling -> %s",
332
391
  request_url,
333
392
  )
@@ -337,32 +396,37 @@ class OTAC:
337
396
  response = requests.post(
338
397
  url=request_url,
339
398
  data=json.dumps(
340
- self.credentials()
399
+ self.credentials(),
341
400
  ), # this includes username + password
342
401
  headers=REQUEST_JSON_HEADERS,
343
402
  timeout=REQUEST_TIMEOUT,
344
403
  )
345
404
  except requests.exceptions.RequestException as exception:
346
- logger.warning(
405
+ self.logger.warning(
347
406
  "Unable to connect to -> %s; error -> %s",
348
407
  request_url,
349
- exception.strerror,
408
+ str(exception),
350
409
  )
351
- logger.warning("OTAC service may not be ready yet.")
410
+ self.logger.warning("OTAC service may not be ready yet.")
352
411
  return None
353
412
 
354
413
  if response.ok:
355
414
  authenticate_list = self.parse_request_response(
356
- response, "This can be normal during restart", False
415
+ response_object=response,
416
+ additional_error_message="This can be normal during restart",
417
+ show_error=False,
357
418
  )
358
419
  if not authenticate_list:
359
420
  return None
360
421
  else:
361
422
  authenticate_dict = authenticate_list[1]
362
423
  otac_ticket = authenticate_dict["TOKEN"]
363
- logger.debug("Ticket -> %s", otac_ticket)
424
+ self.logger.debug("Ticket -> %s", otac_ticket)
364
425
  else:
365
- logger.error("Failed to request an OTAC ticket; error -> %s", response.text)
426
+ self.logger.error(
427
+ "Failed to request an OTAC ticket; error -> %s",
428
+ response.text,
429
+ )
366
430
  return None
367
431
 
368
432
  # Store authentication ticket:
@@ -373,12 +437,15 @@ class OTAC:
373
437
  # end method definition
374
438
 
375
439
  def authenticate_soap(self) -> str:
376
- """Authenticate via SOAP with admin User
440
+ """Authenticate via SOAP with admin User.
377
441
 
378
442
  Args:
379
443
  None
444
+
380
445
  Returns:
381
- string: soap_token
446
+ str:
447
+ The string with the SOAP token.
448
+
382
449
  """
383
450
 
384
451
  url = self.base_url() + "/archive/services/Authentication?wsdl"
@@ -393,12 +460,16 @@ class OTAC:
393
460
  # end method definition
394
461
 
395
462
  def exec_command(self, command: str) -> dict:
396
- """Execute a command on Archive Center
463
+ """Execute a command on Archive Center.
397
464
 
398
465
  Args:
399
- command (str): command to execute
466
+ command (str):
467
+ The command to execute.
468
+
400
469
  Returns:
401
- dict: Response of the HTTP request.
470
+ dict:
471
+ The response of the HTTP request.
472
+
402
473
  """
403
474
 
404
475
  payload = {
@@ -408,17 +479,20 @@ class OTAC:
408
479
  }
409
480
 
410
481
  request_url = self.exec_url()
411
- logger.info(
482
+ self.logger.info(
412
483
  "Execute command -> %s on Archive Center (user -> %s); calling -> %s",
413
484
  command,
414
485
  payload["user"],
415
486
  request_url,
416
487
  )
417
488
  response = requests.post(
418
- url=request_url, data=payload, headers=REQUEST_FORM_HEADERS, timeout=None
489
+ url=request_url,
490
+ data=payload,
491
+ headers=REQUEST_FORM_HEADERS,
492
+ timeout=REQUEST_TIMEOUT,
419
493
  )
420
494
  if not response.ok:
421
- logger.error(
495
+ self.logger.error(
422
496
  "Failed to execute command -> %s on Archive Center; error -> %s",
423
497
  command,
424
498
  response.text.replace("\n", " "), # avoid multi-line log entries
@@ -434,39 +508,50 @@ class OTAC:
434
508
  logical_archive: str,
435
509
  cert_path: str,
436
510
  permissions: str = "rcud",
437
- ):
438
- """Put Certificate on Archive Center via SOAP Call
511
+ ) -> dict | None:
512
+ """Put Certificate on Archive Center via SOAP Call.
439
513
 
440
514
  Args:
441
- auth_id (str): ID of Certification
442
- logical_archive (str): Archive ID
443
- cert_path (str): local path to certificate (base64)
444
- permissions (str, optional): Permissions of the certificate.
445
- Defaults to "rcud" (read-create-update-delete).
515
+ auth_id (str):
516
+ ID of Certification
517
+ logical_archive (str):
518
+ The Archive ID.
519
+ cert_path (str):
520
+ The path to local certificate file (base64 encoded).
521
+ permissions (str, optional):
522
+ Permissions of the certificate.
523
+ Defaults to "rcud" (read-create-update-delete).
524
+
446
525
  Returns:
447
- response or None if the request fails
526
+ Response or None if the request fails.
527
+
448
528
  """
449
529
 
450
530
  # Check if the photo file exists
451
531
  if not os.path.isfile(cert_path):
452
- logger.error("Certificate file -> '%s' not found!", cert_path)
532
+ self.logger.error("Certificate file -> '%s' not found!", cert_path)
453
533
  return None
454
534
 
455
- with open(file=cert_path, mode="r", encoding="utf-8") as cert_file:
535
+ with open(file=cert_path, encoding="utf-8") as cert_file:
456
536
  cert_content = cert_file.read().strip()
457
537
 
458
538
  # Check that we have the pem certificate file - this is what OTAC expects.
459
539
  # If the file content is base64 encoded we will decode it
460
540
  if "BEGIN CERTIFICATE" in cert_content:
461
- logger.debug("Certificate file -> '%s' is not base64 encoded", cert_path)
541
+ self.logger.debug(
542
+ "Certificate file -> '%s' is not base64 encoded",
543
+ cert_path,
544
+ )
462
545
  elif "BEGIN CERTIFICATE" in base64.b64decode(
463
- cert_content, validate=True
546
+ cert_content,
547
+ validate=True,
464
548
  ).decode("utf-8"):
465
- logger.debug("Certificate file -> '%s' is base64 encoded", cert_path)
549
+ self.logger.debug("Certificate file -> '%s' is base64 encoded", cert_path)
466
550
  cert_content = base64.b64decode(cert_content, validate=True).decode("utf-8")
467
551
  else:
468
- logger.error(
469
- "Certificate file -> '%s' is not in the right format", cert_path
552
+ self.logger.error(
553
+ "Certificate file -> '%s' is not in the right format",
554
+ cert_path,
470
555
  )
471
556
  return None
472
557
 
@@ -479,7 +564,7 @@ class OTAC:
479
564
  + "&permissions="
480
565
  + permissions
481
566
  )
482
- logger.debug(
567
+ self.logger.debug(
483
568
  "Putting certificate -> '%s' on Archive -> '%s'; calling -> %s",
484
569
  cert_path,
485
570
  logical_archive,
@@ -489,14 +574,14 @@ class OTAC:
489
574
  url=request_url,
490
575
  data=cert_content,
491
576
  headers=REQUEST_FORM_HEADERS,
492
- timeout=None,
577
+ timeout=REQUEST_TIMEOUT,
493
578
  )
494
579
 
495
580
  if not response.ok:
496
581
  message = response.text.split(
497
- '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN'
582
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN',
498
583
  )[0]
499
- logger.error(
584
+ self.logger.error(
500
585
  "Failed to put certificate -> '%s' on Archive -> '%s'; error -> %s",
501
586
  cert_path,
502
587
  logical_archive,
@@ -508,16 +593,24 @@ class OTAC:
508
593
  # end method definition
509
594
 
510
595
  def enable_cert(
511
- self, auth_id: str, logical_archive: str, enable: bool = True
596
+ self,
597
+ auth_id: str,
598
+ logical_archive: str,
599
+ enable: bool = True,
512
600
  ) -> bool:
513
- """Enables Certitificate on Archive Center via SOAP call
601
+ """Enable Certitificate on Archive Center via SOAP call.
514
602
 
515
603
  Args:
516
- auth_id (str): Client ID
517
- logical_archive (str): Archive ID
518
- enable (bool, optional): Enable or Disable certificate. Defaults to True.
604
+ auth_id (str):
605
+ The authorization ID.
606
+ logical_archive (str):
607
+ The logical archive.
608
+ enable (bool, optional):
609
+ Enable or Disable certificate. Defaults to True.
610
+
519
611
  Returns:
520
612
  True if certificate has been activated, False if an error has occured.
613
+
521
614
  """
522
615
 
523
616
  if not self._soap_token:
@@ -546,42 +639,48 @@ class OTAC:
546
639
  )
547
640
  # With SOAP, no response is a good response!
548
641
  if not response:
549
- logger.debug("Archive Center certificate has been activated.")
642
+ self.logger.debug("Archive Center certificate has been activated.")
550
643
  return True
551
644
  elif response.code == 500:
552
- logger.error(
645
+ self.logger.error(
553
646
  "Failed to activate Archive Center certificate for Client -> %s on Archive -> '%s'!",
554
647
  auth_id,
555
648
  logical_archive,
556
649
  )
557
650
  return False
558
651
 
559
- except WebFault as exception:
560
- logger.error(
561
- "Failed to execute SetCertificateFlags for Client -> %s on Archive -> '%s'; error -> %s",
652
+ except WebFault:
653
+ self.logger.error(
654
+ "Failed to execute SetCertificateFlags for Client -> %s on Archive -> '%s'",
562
655
  auth_id,
563
656
  logical_archive,
564
- exception,
565
657
  )
566
658
  return False
567
659
 
568
660
  # end method definition
569
661
 
570
662
  def enable_certificate(
571
- self, cert_name: str, cert_type: str, logical_archive: str | None = None
663
+ self,
664
+ cert_name: str,
665
+ cert_type: str,
666
+ logical_archive: str | None = None,
572
667
  ) -> dict | None:
573
- """Enable a certificate via the new REST API (replacing the old SOAP interface)
668
+ """Enable a certificate via the new REST API (replacing the old SOAP interface).
574
669
 
575
670
  Args:
576
- cert_name (str): Name of the certificate
577
- cert_type (str): Type of the certificate
578
- logical_archive (str, optional): Logical archive name. If empty it is a global certificate
579
- for all logical archives in Archive Center.
671
+ cert_name (str):
672
+ The name of the certificate.
673
+ cert_type (str):
674
+ The type of the certificate.
675
+ logical_archive (str, optional):
676
+ Logical archive name. If empty it is a global certificate
677
+ for all logical archives in Archive Center.
580
678
 
581
679
  Returns:
582
- dict | None: REST response or None if the request fails
680
+ dict | None:
681
+ REST response or None if the request fails
583
682
 
584
- Example response:
683
+ Example:
585
684
  {
586
685
  'IDNO': '3',
587
686
  'CERT_NAME': 'SP_otcs-admin-0',
@@ -593,15 +692,10 @@ class OTAC:
593
692
  'CERTIFICATE': '...',
594
693
  'PRIVILEGES': {'read': True, 'create': True, 'update': True, 'delete': True}
595
694
  }
695
+
596
696
  """
597
697
 
598
- request_url = (
599
- self.config()["certUrl"]
600
- + "?cert_name="
601
- + cert_name
602
- + "&cert_type="
603
- + cert_type
604
- )
698
+ request_url = self.config()["certUrl"] + "?cert_name=" + cert_name + "&cert_type=" + cert_type
605
699
  if logical_archive:
606
700
  request_url += "&assigned_archive=" + logical_archive
607
701
 
@@ -609,7 +703,7 @@ class OTAC:
609
703
 
610
704
  payload = {"ENABLED": True}
611
705
 
612
- logger.debug(
706
+ self.logger.debug(
613
707
  "Enabling certificate -> '%s' of type -> '%s' to Archive Center; calling -> %s",
614
708
  cert_name,
615
709
  cert_type,
@@ -625,18 +719,18 @@ class OTAC:
625
719
  timeout=REQUEST_TIMEOUT,
626
720
  )
627
721
  if response.ok:
628
- logger.debug(
722
+ self.logger.debug(
629
723
  "Certificate -> '%s' has been enabled on Archive Center keystore",
630
724
  cert_name,
631
725
  )
632
726
  return self.parse_request_response(response)
633
727
  # Check if Session has expired - then re-authenticate and try once more
634
728
  elif response.status_code == 401 and retries == 0:
635
- logger.debug("Session has expired - try to re-authenticate...")
729
+ self.logger.debug("Session has expired - try to re-authenticate...")
636
730
  self.authenticate(revalidate=True)
637
731
  retries += 1
638
732
  else:
639
- logger.error(
733
+ self.logger.error(
640
734
  "Failed to enable certificate -> '%s' in Archive Center; status -> %s; error -> %s",
641
735
  cert_name,
642
736
  response.status_code,