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/coreshare.py CHANGED
@@ -1,91 +1,53 @@
1
- """
2
- CoreShare Module to interact with the Core Share API
3
- See: https://confluence.opentext.com/pages/viewpage.action?spaceKey=OTC&title=APIs+Consumption+based+on+roles
4
- See also: https://swagger.otxlab.net/ui/?branch=master&yaml=application-specific/core/core-api.yaml
1
+ """CoreShare Module to interact with the Core Share API.
2
+
3
+ See:
4
+ - [Confluence](https://confluence.opentext.com/pages/viewpage.action?spaceKey=OTC&title=APIs+Consumption+based+on+roles)
5
+ - [swagger.otxlab.net](https://swagger.otxlab.net/ui/?branch=master&yaml=application-specific/core/core-api.yaml)
5
6
 
6
7
  Authentication - get Client Secrets:
7
- 1. Login to Core Share as a Tenant Admin User .
8
- 2. Navigate to Security P age.
9
- 3. On OAuth Confidential Clients section provide Description and Redirect URLs. It will populate a
10
- dialog with Client Secret.
11
- 4. Copy Client Secret as it will not be available anywhere once the dialog is closed.
12
-
13
- Class: CoreShare
14
- Methods:
15
-
16
- __init__ : class initializer
17
- config : Returns config data set
18
- credentials: Get credentials (username + password)
19
- set_credentials: Set the credentials for Core Share based on username and password.
20
-
21
- request_header_admin: Returns the request header used for Application calls
22
- that require administrator credentials
23
- request_header_user: Returns the request header used for Application calls
24
- that require user (non-admin) credentials.
25
- do_request: call an Core Share REST API in a safe way.
26
- parse_request_response: Parse the REST API responses and convert
27
- them to Python dict in a safe way
28
- lookup_result_value: Lookup a property value based on a provided key / value pair in the response
29
- properties of a Core Share REST API call
30
- exist_result_item: Check if an dict item is in the response
31
- of the Core Share API call
32
- get_result_value: Check if a defined value (based on a key) is in the Core Share API response
33
-
34
- authenticate_admin : Authenticates as Admin at Core Share API
35
- authenticate_user : Authenticates as Service user at Core Share API
36
-
37
- get_groups: Get Core Share groups.
38
- add_group: Add a new Core Share group.
39
- get_group_members: Get Core Share group members.
40
- add_group_member: Add a Core Share user to a Cire Share group.
41
- remove_group_member: Remove a Core Share user from a Core Share group.
42
- get_group_by_id: Get a Core Share group by its ID.
43
- get_group_by_name: Get Core Share group by its name.
44
- search_groups: Search Core Share group(s) by name.
45
-
46
- get_users: Get Core Share users.
47
- get_user_by_id: Get a Core Share user by its ID.
48
- get_user_by_name: Get Core Share user by its first and last name.
49
- search_users: Search Core Share user(s) by name / property.
50
- add_user: Add a new Core Share user. This requires a Tenent Admin authorization.
51
- resend_user_invite: Resend the invite for a Core Share user.
52
- update_user: Update a Core Share user.
53
- add_user_access_role: Add an access role to a Core Share user.
54
- remove_user_access_role: Remove an access role from a Core Share user.
55
- update_user_access_roles: Define the access roles of a Core Share user.
56
- update_user_password: Update the password of a Core Share user.
57
- update_user_photo: Update the Core Share user photo.
58
-
59
- get_folders: Get Core Share folders under a given parent ID.
60
- unshare_folder: Unshare Core Share folder with a given resource ID.
61
- delete_folder: Delete Core Share folder with a given resource ID.
62
- delete_document: Delete Core Share document with a given resource ID.
63
- leave_share: Remove a Core Share user from a share (i.e. the user leaves the share)
64
- stop_share: Stop of share of a user.
65
- cleanup_user_files: Cleanup all files of a user. This handles different types of resources.
66
- get_group_shares: Get (incoming) shares of a Core Share group.
67
- revoke_group_share: Revoke sharing of a folder with a group.
68
- cleanup_group_shares: Cleanup all incoming shares of a group.
8
+ 1. Login to Core Share as a Tenant Admin User.
9
+ 2. Navigate to Security Page.
10
+ 3. On OAuth Confidential Clients section provide Description and Redirect URLs. It will populate a
11
+ dialog with Client Secret.
12
+ 4. Copy Client Secret as it will not be available anywhere once the dialog is closed.
69
13
  """
70
14
 
71
15
  __author__ = "Dr. Marc Diefenbruch"
72
- __copyright__ = "Copyright 2024, OpenText"
16
+ __copyright__ = "Copyright (C) 2024-2025, OpenText"
73
17
  __credits__ = ["Kai-Philip Gatzweiler"]
74
18
  __maintainer__ = "Dr. Marc Diefenbruch"
75
19
  __email__ = "mdiefenb@opentext.com"
76
20
 
77
- import os
78
21
  import json
79
22
  import logging
23
+ import os
24
+ import platform
25
+ import sys
80
26
  import time
81
-
82
27
  import urllib.parse
83
28
  from http import HTTPStatus
29
+ from importlib.metadata import version
30
+
84
31
  import requests
85
32
 
86
- logger = logging.getLogger("pyxecm.customizer.coreshare")
33
+ APP_NAME = "pyxecm"
34
+ APP_VERSION = version("pyxecm")
35
+ MODULE_NAME = APP_NAME + ".coreshare"
36
+
37
+ PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
38
+ OS_INFO = f"{platform.system()} {platform.release()}"
39
+ ARCH_INFO = platform.machine()
40
+ REQUESTS_VERSION = requests.__version__
41
+
42
+ USER_AGENT = (
43
+ f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
44
+ f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
45
+ )
46
+
47
+ default_logger = logging.getLogger(MODULE_NAME)
87
48
 
88
49
  REQUEST_LOGIN_HEADERS = {
50
+ "User-Agent": USER_AGENT,
89
51
  "Content-Type": "application/x-www-form-urlencoded",
90
52
  "Accept": "application/json",
91
53
  }
@@ -94,9 +56,14 @@ REQUEST_TIMEOUT = 60
94
56
  REQUEST_RETRY_DELAY = 20
95
57
  REQUEST_MAX_RETRIES = 2
96
58
 
59
+ CONTENT_MANAGER_ROLE_ID = 5
60
+ GROUP_ADMIN_ROLE_ID = 3
61
+
97
62
 
98
- class CoreShare(object):
99
- """Used to retrieve and automate stettings in Core Share."""
63
+ class CoreShare:
64
+ """Class CoreShare is used to retrieve and automate settings and objects (users, groups) in Core Share."""
65
+
66
+ logger: logging.Logger = default_logger
100
67
 
101
68
  _config: dict
102
69
  _access_token_user = None
@@ -110,17 +77,31 @@ class CoreShare(object):
110
77
  client_secret: str,
111
78
  username: str,
112
79
  password: str,
113
- ):
114
- """Initialize the CoreShare object
80
+ logger: logging.Logger = default_logger,
81
+ ) -> None:
82
+ """Initialize the CoreShare object.
115
83
 
116
84
  Args:
117
- base_url (str): base URL of the Core Share tenant
118
- sso_url (str): Single Sign On URL of the Core Share tenant
119
- client_id (str): Core Share Client ID
120
- client_secret (str): Core Share Client Secret
121
- username (str): admin user name in Core Share
122
- password (str): admin password in Core Share
85
+ base_url (str):
86
+ The base URL of the Core Share tenant.
87
+ sso_url (str):
88
+ The single sign on URL of the Core Share tenant.
89
+ client_id (str):
90
+ The Core Share Client ID.
91
+ client_secret (str):
92
+ The Core Share client secret.
93
+ username (str):
94
+ The admin user name in Core Share.
95
+ password (str):
96
+ The admin password in Core Share.
97
+ logger (logging.Logger, optional):
98
+ The logging object to use for all log messages. Defaults to default_logger.
99
+
123
100
  """
101
+ if logger != default_logger:
102
+ self.logger = logger.getChild("coreshare")
103
+ for logfilter in logger.filters:
104
+ self.logger.addFilter(logfilter)
124
105
 
125
106
  core_share_config = {}
126
107
 
@@ -141,22 +122,14 @@ class CoreShare(object):
141
122
  core_share_config["invitesUrl"] = core_share_config["restUrlv1"] + "/invites"
142
123
  core_share_config["foldersUrlv1"] = core_share_config["restUrlv1"] + "/folders"
143
124
  core_share_config["foldersUrlv3"] = core_share_config["restUrlv3"] + "/folders"
144
- core_share_config["documentsUrlv1"] = (
145
- core_share_config["restUrlv1"] + "/documents"
146
- )
147
- core_share_config["documentsUrlv3"] = (
148
- core_share_config["restUrlv3"] + "/documents"
149
- )
125
+ core_share_config["documentsUrlv1"] = core_share_config["restUrlv1"] + "/documents"
126
+ core_share_config["documentsUrlv3"] = core_share_config["restUrlv3"] + "/documents"
150
127
  core_share_config["searchUrl"] = core_share_config["baseUrl"] + "/search/v1"
151
128
  core_share_config["searchUserUrl"] = core_share_config["searchUrl"] + "/user"
152
- core_share_config["searchGroupUrl"] = (
153
- core_share_config["searchUrl"] + "/user/group-all"
154
- )
129
+ core_share_config["searchGroupUrl"] = core_share_config["searchUrl"] + "/user/group-all"
155
130
 
156
131
  core_share_config["sessionsUrl"] = core_share_config["restUrlv1"] + "/sessions"
157
- core_share_config["tokenUrl"] = (
158
- core_share_config["ssoUrl"] + "/otdsws/oauth2/token"
159
- )
132
+ core_share_config["tokenUrl"] = core_share_config["ssoUrl"] + "/otdsws/oauth2/token"
160
133
  core_share_config["sessionsUrl"] = core_share_config["restUrlv1"] + "/sessions"
161
134
 
162
135
  # Tenant Admin User Authentication information (Session URL):
@@ -196,21 +169,27 @@ class CoreShare(object):
196
169
  # end method definition
197
170
 
198
171
  def config(self) -> dict:
199
- """Returns the configuration dictionary
172
+ """Return the configuration dictionary.
200
173
 
201
174
  Returns:
202
- dict: Configuration dictionary
175
+ dict:
176
+ The configuration dictionary.
177
+
203
178
  """
179
+
204
180
  return self._config
205
181
 
206
182
  # end method definition
207
183
 
208
184
  def credentials(self) -> dict:
209
- """Get credentials (username + password)
185
+ """Get credentials (username + password).
210
186
 
211
187
  Returns:
212
- dict: dictionary with username and password
188
+ dict:
189
+ A dictionary with username and password.
190
+
213
191
  """
192
+
214
193
  return {
215
194
  "username": self.config()["username"],
216
195
  "password": self.config()["password"],
@@ -218,15 +197,16 @@ class CoreShare(object):
218
197
 
219
198
  # end method definition
220
199
 
221
- def set_credentials(self, username: str = "admin", password: str = ""):
200
+ def set_credentials(self, username: str = "admin", password: str = "") -> None:
222
201
  """Set the credentials for Core Share based on username and password.
223
202
 
224
203
  Args:
225
204
  username (str, optional): Username. Defaults to "admin".
226
205
  password (str, optional): Password of the user. Defaults to "".
206
+
227
207
  """
228
208
 
229
- logger.info("Change Core Share credentials to user -> %s...", username)
209
+ self.logger.info("Change Core Share credentials to user -> %s...", username)
230
210
 
231
211
  self.config()["username"] = username
232
212
  self.config()["password"] = password
@@ -258,17 +238,27 @@ class CoreShare(object):
258
238
  # end method definition
259
239
 
260
240
  def request_header_admin(self, content_type: str = "application/json") -> dict:
261
- """Returns the request header used for Application calls
262
- that require administrator credentials.
263
- Consists of Bearer access token and Content Type
241
+ """Return the request header used for application calls that require administrator credentials.
242
+
243
+ Consists of Bearer access token and Content Type
264
244
 
265
245
  Args:
266
- content_type (str, optional): content type for the request
246
+ content_type (str, optional):
247
+ Custom content type for the request.
248
+ Typical values:
249
+ * application/json - Used for sending JSON-encoded data
250
+ * application/x-www-form-urlencoded - The default for HTML forms.
251
+ Data is sent as key-value pairs in the body of the request, similar to query parameters.
252
+ * multipart/form-data - Used for file uploads or when a form includes non-ASCII characters
253
+
267
254
  Return:
268
- dict: request header values
255
+ dict:
256
+ The request header values.
257
+
269
258
  """
270
259
 
271
260
  request_header = {
261
+ "User-Agent": USER_AGENT,
272
262
  "Authorization": "Bearer {}".format(self._access_token_admin),
273
263
  }
274
264
  if content_type:
@@ -279,17 +269,22 @@ class CoreShare(object):
279
269
  # end method definition
280
270
 
281
271
  def request_header_user(self, content_type: str = "application/json") -> dict:
282
- """Returns the request header used for Application calls
283
- that require user (non-admin) credentials.
284
- Consists of Bearer access token and Content Type
272
+ """Return the request header used for Application calls that require user (non-admin) credentials.
273
+
274
+ Consists of Bearer access token and Content Type
285
275
 
286
276
  Args:
287
- content_type (str, optional): content type for the request
277
+ content_type (str, optional):
278
+ The content type for the request.
279
+
288
280
  Return:
289
- dict: request header values
281
+ dict:
282
+ The request header values.
283
+
290
284
  """
291
285
 
292
286
  request_header = {
287
+ "User-Agent": USER_AGENT,
293
288
  "Authorization": "Bearer {}".format(self._access_token_user),
294
289
  }
295
290
  if content_type:
@@ -319,33 +314,61 @@ class CoreShare(object):
319
314
  user_credentials: bool = False,
320
315
  verify: bool = True,
321
316
  ) -> dict | None:
322
- """Call an OTDS REST API in a safe way
317
+ """Call an OTDS REST API in a safe way.
323
318
 
324
319
  Args:
325
- url (str): URL to send the request to.
326
- method (str, optional): HTTP method (GET, POST, etc.). Defaults to "GET".
327
- headers (dict | None, optional): Request Headers. Defaults to None.
328
- data (dict | None, optional): Request payload. Defaults to None
329
- files (dict | None, optional): Dictionary of {"name": file-tuple} for multipart encoding upload.
330
- file-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple ("filename", fileobj, "content_type")
331
- timeout (int | None, optional): Timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
332
- show_error (bool, optional): Whether or not an error should be logged in case of a failed REST call.
333
- If False, then only a warning is logged. Defaults to True.
334
- warning_message (str, optional): Specific warning message. Defaults to "". If not given the error_message will be used.
335
- failure_message (str, optional): Specific error message. Defaults to "".
336
- success_message (str, optional): Specific success message. Defaults to "".
337
- max_retries (int, optional): How many retries on Connection errors? Default is REQUEST_MAX_RETRIES.
338
- retry_forever (bool, optional): Eventually wait forever - without timeout. Defaults to False.
339
- parse_request_response (bool, optional): should the response.text be interpreted as json and loaded into a dictionary. True is the default.
340
- user_credentials (bool, optional): defines if admin or user credentials are used for the REST API call. Default = False = admin credentials
341
- verify (bool, optional): specify whether or not SSL certificates should be verified when making an HTTPS request. Default = True
320
+ url (str):
321
+ The URL to send the request to.
322
+ method (str, optional):
323
+ HTTP method (GET, POST, etc.). Defaults to "GET".
324
+ headers (dict | None, optional):
325
+ Request Headers. Defaults to None.
326
+ data (dict | None, optional):
327
+ Request payload. Defaults to None
328
+ json_data (dict | None, optional):
329
+ Request payload for the JSON parameter. Defaults to None.
330
+ files (dict | None, optional):
331
+ Dictionary of {"name": file-tuple} for multipart encoding upload.
332
+ The file-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple ("filename", fileobj, "content_type")
333
+ timeout (int | None, optional):
334
+ Timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
335
+ show_error (bool, optional):
336
+ Whether or not an error should be logged in case of a failed REST call.
337
+ If False, then only a warning is logged. Defaults to True.
338
+ show_warning (bool, optional):
339
+ Whether or not an warning should be logged in case of a
340
+ failed REST call.
341
+ If False, then only a warning is logged. Defaults to True.
342
+ warning_message (str, optional):
343
+ Specific warning message. Defaults to "". If not given the error_message will be used.
344
+ failure_message (str, optional):
345
+ Specific error message. Defaults to "".
346
+ success_message (str, optional):
347
+ Specific success message. Defaults to "".
348
+ max_retries (int, optional):
349
+ How many retries on Connection errors? Default is REQUEST_MAX_RETRIES.
350
+ retry_forever (bool, optional):
351
+ Eventually wait forever - without timeout. Defaults to False.
352
+ parse_request_response (bool, optional):
353
+ If True the response.text will be interpreted as json and loaded into a dictionary.
354
+ True is the default.
355
+ user_credentials (bool, optional):
356
+ Defines if admin or user credentials are used for the REST API call.
357
+ Default = False = admin credentials
358
+ verify (bool, optional):
359
+ Specify whether or not SSL certificates should be verified when making an HTTPS request.
360
+ Default = True
342
361
 
343
362
  Returns:
344
- dict | None: Response of OTDS REST API or None in case of an error.
363
+ dict | None:
364
+ Response of OTDS REST API or None in case of an error.
365
+
345
366
  """
346
367
 
347
368
  if headers is None:
348
- logger.error("Missing request header. Cannot send request to Core Share!")
369
+ self.logger.error(
370
+ "Missing request header. Cannot send request to Core Share!",
371
+ )
349
372
  return None
350
373
 
351
374
  # In case of an expired session we reauthenticate and
@@ -368,7 +391,7 @@ class CoreShare(object):
368
391
 
369
392
  if response.ok:
370
393
  if success_message:
371
- logger.info(success_message)
394
+ self.logger.info(success_message)
372
395
  if parse_request_response:
373
396
  return self.parse_request_response(response)
374
397
  else:
@@ -376,22 +399,22 @@ class CoreShare(object):
376
399
  # Check if Session has expired - then re-authenticate and try once more
377
400
  elif response.status_code == 401 and retries == 0:
378
401
  if user_credentials:
379
- logger.debug(
380
- "User session has expired - try to re-authenticate..."
402
+ self.logger.debug(
403
+ "User session has expired - try to re-authenticate...",
381
404
  )
382
405
  self.authenticate_user(revalidate=True)
383
406
  # Make sure to not change the content type:
384
407
  headers = self.request_header_user(
385
- content_type=headers.get("Content-Type", None)
408
+ content_type=headers.get("Content-Type", None),
386
409
  )
387
410
  else:
388
- logger.warning(
389
- "Admin session has expired - try to re-authenticate..."
411
+ self.logger.warning(
412
+ "Admin session has expired - try to re-authenticate...",
390
413
  )
391
414
  self.authenticate_admin(revalidate=True)
392
415
  # Make sure to not change the content type:
393
416
  headers = self.request_header_admin(
394
- content_type=headers.get("Content-Type", None)
417
+ content_type=headers.get("Content-Type", None),
395
418
  )
396
419
  retries += 1
397
420
  else:
@@ -405,7 +428,7 @@ class CoreShare(object):
405
428
  response_text = response.text
406
429
 
407
430
  if show_error:
408
- logger.error(
431
+ self.logger.error(
409
432
  "%s; status -> %s/%s; error -> %s",
410
433
  failure_message,
411
434
  response.status_code,
@@ -413,7 +436,7 @@ class CoreShare(object):
413
436
  response_text,
414
437
  )
415
438
  elif show_warning:
416
- logger.warning(
439
+ self.logger.warning(
417
440
  "%s; status -> %s/%s; warning -> %s",
418
441
  warning_message if warning_message else failure_message,
419
442
  response.status_code,
@@ -421,7 +444,7 @@ class CoreShare(object):
421
444
  response_text,
422
445
  )
423
446
  if content_type == "text/html":
424
- logger.debug(
447
+ self.logger.debug(
425
448
  "%s; status -> %s/%s; warning -> %s",
426
449
  failure_message,
427
450
  response.status_code,
@@ -431,45 +454,45 @@ class CoreShare(object):
431
454
  return None
432
455
  except requests.exceptions.Timeout:
433
456
  if retries <= max_retries:
434
- logger.warning(
457
+ self.logger.warning(
435
458
  "Request timed out. Retrying in %s seconds...",
436
459
  str(REQUEST_RETRY_DELAY),
437
460
  )
438
461
  retries += 1
439
462
  time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
440
463
  else:
441
- logger.error(
442
- "%s; timeout error",
464
+ self.logger.error(
465
+ "%s; timeout error.",
443
466
  failure_message,
444
467
  )
445
468
  if retry_forever:
446
469
  # If it fails after REQUEST_MAX_RETRIES retries we let it wait forever
447
- logger.warning("Turn timeouts off and wait forever...")
470
+ self.logger.warning("Turn timeouts off and wait forever...")
448
471
  timeout = None
449
472
  else:
450
473
  return None
451
474
  except requests.exceptions.ConnectionError:
452
475
  if retries <= max_retries:
453
- logger.warning(
476
+ self.logger.warning(
454
477
  "Connection error. Retrying in %s seconds...",
455
478
  str(REQUEST_RETRY_DELAY),
456
479
  )
457
480
  retries += 1
458
481
  time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
459
482
  else:
460
- logger.error(
461
- "%s; connection error",
483
+ self.logger.error(
484
+ "%s; connection error.",
462
485
  failure_message,
463
486
  )
464
487
  if retry_forever:
465
488
  # If it fails after REQUEST_MAX_RETRIES retries we let it wait forever
466
- logger.warning("Turn timeouts off and wait forever...")
489
+ self.logger.warning("Turn timeouts off and wait forever...")
467
490
  timeout = None
468
491
  time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
469
492
  else:
470
493
  return None
471
494
  # end try
472
- logger.debug(
495
+ self.logger.debug(
473
496
  "Retrying REST API %s call -> %s... (retry = %s)",
474
497
  method,
475
498
  url,
@@ -485,43 +508,47 @@ class CoreShare(object):
485
508
  additional_error_message: str = "",
486
509
  show_error: bool = True,
487
510
  ) -> dict | None:
488
- """Converts the request response (JSon) to a Python dict in a safe way
489
- that also handles exceptions. It first tries to load the response.text
490
- via json.loads() that produces a dict output. Only if response.text is
491
- not set or is empty it just converts the response_object to a dict using
492
- the vars() built-in method.
511
+ """Convert the request response to a dict in a safe way.
512
+
513
+ This also handles exceptions. It first tries to load the response.text
514
+ via json.loads() that produces a dict output. Only if response.text is
515
+ not set or is empty it just converts the response_object to a dict using
516
+ the vars() built-in method.
493
517
 
494
518
  Args:
495
- response_object (object): this is reponse object delivered by the request call
496
- additional_error_message (str, optional): use a more specific error message
497
- in case of an error
498
- show_error (bool): True: write an error to the log file
499
- False: write a warning to the log file
519
+ response_object (object):
520
+ This is reponse object returned by the request call.
521
+ additional_error_message (str, optional):
522
+ Can be used to provide a more specific error message
523
+ in case an error occurs.
524
+ show_error (bool, optional):
525
+ True: write an error to the log file
526
+ False: write a warning to the log file
527
+
500
528
  Returns:
501
529
  dict: response information or None in case of an error
530
+
502
531
  """
503
532
 
504
533
  if not response_object:
505
534
  return None
506
535
 
507
536
  try:
508
- if response_object.text:
509
- dict_object = json.loads(response_object.text)
510
- else:
511
- dict_object = vars(response_object)
537
+ dict_object = json.loads(response_object.text) if response_object.text else vars(response_object)
512
538
  except json.JSONDecodeError as exception:
513
539
  if additional_error_message:
514
540
  message = "Cannot decode response as JSon. {}; error -> {}".format(
515
- additional_error_message, exception
541
+ additional_error_message,
542
+ exception,
516
543
  )
517
544
  else:
518
545
  message = "Cannot decode response as JSon; error -> {}".format(
519
- exception
546
+ exception,
520
547
  )
521
548
  if show_error:
522
- logger.error(message)
549
+ self.logger.error(message)
523
550
  else:
524
- logger.warning(message)
551
+ self.logger.warning(message)
525
552
  return None
526
553
  else:
527
554
  return dict_object
@@ -529,24 +556,34 @@ class CoreShare(object):
529
556
  # end method definition
530
557
 
531
558
  def lookup_result_value(
532
- self, response: dict, key: str, value: str, return_key: str
559
+ self,
560
+ response: dict,
561
+ key: str,
562
+ value: str,
563
+ return_key: str,
533
564
  ) -> str | None:
534
- """Lookup a property value based on a provided key / value pair in the
535
- response properties of an Extended ECM REST API call.
565
+ """Lookup a property value based on a provided key / value pair in the response of an Core Share REST API call.
536
566
 
537
567
  Args:
538
- response (dict): REST response from an OTCS REST Call
539
- key (str): property name (key)
540
- value (str): value to find in the item with the matching key
541
- return_key (str): determines which value to return based on the name of the dict key
568
+ response (dict):
569
+ REST response from an Core Share REST Call
570
+ key (str):
571
+ The property name (key).
572
+ value (str):
573
+ The value to find in the item with the matching key.
574
+ return_key (str):
575
+ Determines which value to return based on the name of the dict key.
576
+
542
577
  Returns:
543
- str: value of the property with the key defined in "return_key"
544
- or None if the lookup fails
578
+ str | None:
579
+ The value of the property with the key defined in "return_key"
580
+ or None if the lookup fails.
581
+
545
582
  """
546
583
 
547
584
  if not response:
548
585
  return None
549
- if not "results" in response:
586
+ if "results" not in response:
550
587
  return None
551
588
 
552
589
  results = response["results"]
@@ -562,16 +599,28 @@ class CoreShare(object):
562
599
  # end method definition
563
600
 
564
601
  def exist_result_item(
565
- self, response: dict, key: str, value: str, results_marker: str = "results"
602
+ self,
603
+ response: dict,
604
+ key: str,
605
+ value: str,
606
+ results_marker: str = "results",
566
607
  ) -> bool:
567
608
  """Check existence of key / value pair in the response properties of a Core Share API call.
568
609
 
569
610
  Args:
570
- response (dict): REST response from a Core Share API call
571
- key (str): property name (key)
572
- value (str): value to find in the item with the matching key
611
+ response (dict):
612
+ REST response from a Core Share API call
613
+ key (str):
614
+ A property name (key)
615
+ value (str):
616
+ The value to find in the item with the matching key.
617
+ results_marker (str, optional):
618
+ The name of the data structure for the results.
619
+
573
620
  Returns:
574
- bool: True if the value was found, False otherwise
621
+ bool:
622
+ True, if the value was found, False otherwise.
623
+
575
624
  """
576
625
 
577
626
  if not response:
@@ -586,7 +635,7 @@ class CoreShare(object):
586
635
  if value == result[key]:
587
636
  return True
588
637
  else:
589
- if not key in response:
638
+ if key not in response:
590
639
  return False
591
640
  if value == response[key]:
592
641
  return True
@@ -604,12 +653,18 @@ class CoreShare(object):
604
653
  """Get value of a result property with a given key of a Core Share API call.
605
654
 
606
655
  Args:
607
- response (dict or list): REST response from a Core Share REST Call
608
- key (str): property name (key)
609
- index (int, optional): Index to use (1st element has index 0).
610
- Defaults to 0.
656
+ response (dict or list):
657
+ REST response from a Core Share REST Call
658
+ key (str):
659
+ The property name (key).
660
+ index (int, optional):
661
+ Index to use (1st element has index 0).
662
+ Defaults to 0.
663
+
611
664
  Returns:
612
- str: value for the key, None otherwise
665
+ str:
666
+ The value for the key, None in case of an error.
667
+
613
668
  """
614
669
 
615
670
  if not response:
@@ -619,7 +674,7 @@ class CoreShare(object):
619
674
  if isinstance(response, list):
620
675
  if len(response) - 1 < index:
621
676
  return None
622
- if not key in response[index]:
677
+ if key not in response[index]:
623
678
  return None
624
679
  value = response[index][key]
625
680
  return value
@@ -629,17 +684,13 @@ class CoreShare(object):
629
684
  if "results" in response:
630
685
  # we expect results to be a list!
631
686
  values = response["results"]
632
- if (
633
- not values
634
- or not isinstance(values, list)
635
- or len(values) - 1 < index
636
- ):
687
+ if not values or not isinstance(values, list) or len(values) - 1 < index:
637
688
  return None
638
- if not key in values[index]:
689
+ if key not in values[index]:
639
690
  return None
640
691
  value = values[index][key]
641
692
  else: # simple response as dictionary - try to find key in response directly:
642
- if not key in response:
693
+ if key not in response:
643
694
  return None
644
695
  value = response[key]
645
696
 
@@ -656,15 +707,20 @@ class CoreShare(object):
656
707
  """Authenticate at Core Share as Tenant Admin.
657
708
 
658
709
  Args:
659
- revalidate (bool, optional): determinse if a re-athentication is enforced
660
- (e.g. if session has timed out with 401 error)
710
+ revalidate (bool, optional):
711
+ Defines whether or not a re-athentication is enforced
712
+ (e.g. if session has timed out with 401 error).
713
+
661
714
  Returns:
662
- str: Access token. Also stores access token in self._access_token. None in case of error
715
+ str:
716
+ The access token. Also stores access token in self._access_token.
717
+ None in case of error.
718
+
663
719
  """
664
720
 
665
721
  # Already authenticated and session still valid?
666
722
  if self._access_token_admin and not revalidate:
667
- logger.debug(
723
+ self.logger.debug(
668
724
  "Session still valid - return existing access token -> %s",
669
725
  str(self._access_token_admin),
670
726
  )
@@ -674,7 +730,10 @@ class CoreShare(object):
674
730
 
675
731
  request_header = REQUEST_LOGIN_HEADERS
676
732
 
677
- logger.debug("Requesting Core Share Admin Access Token from -> %s", request_url)
733
+ self.logger.debug(
734
+ "Requesting Core Share Admin Access Token from -> %s",
735
+ request_url,
736
+ )
678
737
 
679
738
  response = None
680
739
  self._access_token_admin = None
@@ -686,7 +745,7 @@ class CoreShare(object):
686
745
  timeout=REQUEST_TIMEOUT,
687
746
  )
688
747
  except requests.exceptions.ConnectionError as exception:
689
- logger.warning(
748
+ self.logger.warning(
690
749
  "Unable to connect to -> %s : %s",
691
750
  request_url,
692
751
  exception,
@@ -709,13 +768,14 @@ class CoreShare(object):
709
768
 
710
769
  # Store authentication access_token:
711
770
  self._access_token_admin = access_token
712
- logger.debug(
713
- "Tenant Admin Access Token -> %s", self._access_token_admin
771
+ self.logger.debug(
772
+ "Tenant Admin Access Token -> %s",
773
+ self._access_token_admin,
714
774
  )
715
775
  else:
716
776
  return None
717
777
  else:
718
- logger.error(
778
+ self.logger.error(
719
779
  "Failed to request a Core Share Tenant Admin Access Token; error -> %s",
720
780
  response.text,
721
781
  )
@@ -726,37 +786,38 @@ class CoreShare(object):
726
786
  # end method definition
727
787
 
728
788
  def authenticate_user(
729
- self, revalidate: bool = False, grant_type: str = "password"
789
+ self,
790
+ revalidate: bool = False,
791
+ grant_type: str = "password",
730
792
  ) -> str | None:
731
793
  """Authenticate at Core Share as Tenant Service User (TSU) with client ID and client secret.
732
794
 
733
795
  Args:
734
- revalidate (bool, optional): determinse if a re-athentication is enforced
735
- (e.g. if session has timed out with 401 error)
736
- grant_type (str, optional): Can either be "client_credentials" (default) or "password".
796
+ revalidate (bool, optional):
797
+ Defines whether or not a re-athentication is enforced
798
+ (e.g. if session has timed out with 401 error).
799
+ grant_type (str, optional):
800
+ Can either be "client_credentials" (default) or "password".
801
+
737
802
  Returns:
738
- str: Access token. Also stores access token in self._access_token. None in case of error
803
+ str:
804
+ The access token. Also stores access token in self._access_token.
805
+ None in case of error.
806
+
739
807
  """
740
808
 
741
809
  # Already authenticated and session still valid?
742
810
  if self._access_token_user and not revalidate:
743
- logger.debug(
811
+ self.logger.debug(
744
812
  "Session still valid - return existing access token -> %s",
745
813
  str(self._access_token_user),
746
814
  )
747
815
  return self._access_token_user
748
816
 
749
- if grant_type == "client_credentials":
750
- request_url = self.config()["authorizationUrlCredentials"]
751
- elif grant_type == "password":
752
- request_url = self.config()["authorizationUrlPassword"]
753
- else:
754
- logger.error("Illegal grant type - authorization not possible!")
755
- return None
756
-
757
817
  request_header = REQUEST_LOGIN_HEADERS
818
+ request_url = self.config()["tokenUrl"]
758
819
 
759
- logger.debug(
820
+ self.logger.debug(
760
821
  "Requesting Core Share Tenant Service User Access Token from -> %s",
761
822
  request_url,
762
823
  )
@@ -764,14 +825,25 @@ class CoreShare(object):
764
825
  response = None
765
826
  self._access_token_user = None
766
827
 
828
+ authentication_body_post = {
829
+ "grant_type": grant_type,
830
+ "client_id": self.config()["clientId"],
831
+ "client_secret": self.config()["clientSecret"],
832
+ }
833
+
834
+ if grant_type == "password":
835
+ authentication_body_post["username"] = self.config()["username"]
836
+ authentication_body_post["password"] = self.config()["password"]
837
+
767
838
  try:
768
839
  response = requests.post(
769
840
  request_url,
770
841
  headers=request_header,
842
+ data=authentication_body_post,
771
843
  timeout=REQUEST_TIMEOUT,
772
844
  )
773
845
  except requests.exceptions.ConnectionError as exception:
774
- logger.warning(
846
+ self.logger.warning(
775
847
  "Unable to connect to -> %s : %s",
776
848
  request_url,
777
849
  exception,
@@ -785,11 +857,12 @@ class CoreShare(object):
785
857
  else:
786
858
  # Store authentication access_token:
787
859
  self._access_token_user = authenticate_dict["access_token"]
788
- logger.debug(
789
- "Tenant Service User Access Token -> %s", self._access_token_user
860
+ self.logger.debug(
861
+ "Tenant Service User Access Token -> %s",
862
+ self._access_token_user,
790
863
  )
791
864
  else:
792
- logger.error(
865
+ self.logger.error(
793
866
  "Failed to request a Core Share Tenant Service User Access Token; error -> %s",
794
867
  response.text,
795
868
  )
@@ -803,11 +876,14 @@ class CoreShare(object):
803
876
  """Get Core Share groups.
804
877
 
805
878
  Args:
806
- offset (int, optional): index of first group (for pagination). Defaults to 0.
807
- count (int, optional): number of groups to return (page length). Defaults to 25.
879
+ offset (int, optional):
880
+ The index of first group (for pagination). Defaults to 0.
881
+ count (int, optional):
882
+ The number of groups to return (page length). Defaults to 25.
808
883
 
809
884
  Returns:
810
- dict | None: Dictionary with the Core Share group data or None if the request fails.
885
+ dict | None:
886
+ Dictionary with the Core Share group data or None if the request fails.
811
887
 
812
888
  Example response:
813
889
  {
@@ -832,6 +908,7 @@ class CoreShare(object):
832
908
  }
833
909
  ]
834
910
  }
911
+
835
912
  """
836
913
 
837
914
  if not self._access_token_user:
@@ -839,10 +916,11 @@ class CoreShare(object):
839
916
 
840
917
  request_header = self.request_header_user()
841
918
  request_url = self.config()["groupsUrl"] + "?offset={}&count={}".format(
842
- offset, count
919
+ offset,
920
+ count,
843
921
  )
844
922
 
845
- logger.debug("Get Core Share groups; calling -> %s", request_url)
923
+ self.logger.debug("Get Core Share groups; calling -> %s", request_url)
846
924
 
847
925
  return self.do_request(
848
926
  url=request_url,
@@ -863,11 +941,14 @@ class CoreShare(object):
863
941
  """Add a new Core Share group. This requires a Tenent Admin authorization.
864
942
 
865
943
  Args:
866
- group_name (str): Name of the new Core Share group
867
- description (str): Description of the new Core Share group
944
+ group_name (str):
945
+ The name of the new Core Share group.
946
+ description (str, optional):
947
+ The description of the new Core Share group.
868
948
 
869
949
  Returns:
870
- dict | None: Dictionary with the Core Share Group data or None if the request fails.
950
+ dict | None:
951
+ Dictionary with the Core Share Group data or None if the request fails.
871
952
 
872
953
  Example response:
873
954
  {
@@ -887,6 +968,7 @@ class CoreShare(object):
887
968
  "isSync": false,
888
969
  "tenantId": "2157293035593927996"
889
970
  }
971
+
890
972
  """
891
973
 
892
974
  if not self._access_token_admin:
@@ -897,8 +979,10 @@ class CoreShare(object):
897
979
 
898
980
  payload = {"name": group_name, "description": description}
899
981
 
900
- logger.debug(
901
- "Adding Core Share group -> %s; calling -> %s", group_name, request_url
982
+ self.logger.debug(
983
+ "Adding Core Share group -> %s; calling -> %s",
984
+ group_name,
985
+ request_url,
902
986
  )
903
987
 
904
988
  return self.do_request(
@@ -917,10 +1001,12 @@ class CoreShare(object):
917
1001
  """Get Core Share group members.
918
1002
 
919
1003
  Args:
920
- group_id (str): ID of the group to deliver the members for.
1004
+ group_id (str):
1005
+ The ID of the group to deliver the members for.
921
1006
 
922
1007
  Returns:
923
- dict | None: Dictionary with the Core Share group membership data or None if the request fails.
1008
+ dict | None:
1009
+ Dictionary with the Core Share group membership data or None if the request fails.
924
1010
 
925
1011
  Example response:
926
1012
  {
@@ -949,6 +1035,7 @@ class CoreShare(object):
949
1035
  ],
950
1036
  'count': 0
951
1037
  }
1038
+
952
1039
  """
953
1040
 
954
1041
  if not self._access_token_admin:
@@ -957,7 +1044,7 @@ class CoreShare(object):
957
1044
  request_header = self.request_header_admin()
958
1045
  request_url = self.config()["groupsUrl"] + "/{}".format(group_id) + "/members"
959
1046
 
960
- logger.debug(
1047
+ self.logger.debug(
961
1048
  "Get members for Core Share group with ID -> %s; calling -> %s",
962
1049
  group_id,
963
1050
  request_url,
@@ -969,7 +1056,7 @@ class CoreShare(object):
969
1056
  headers=request_header,
970
1057
  timeout=REQUEST_TIMEOUT,
971
1058
  failure_message="Failed to get members of Core Share group -> '{}'".format(
972
- group_id
1059
+ group_id,
973
1060
  ),
974
1061
  user_credentials=False,
975
1062
  )
@@ -977,16 +1064,25 @@ class CoreShare(object):
977
1064
  # end method definition
978
1065
 
979
1066
  def add_group_member(
980
- self, group_id: str, user_id: str, is_group_admin: bool = False
1067
+ self,
1068
+ group_id: str,
1069
+ user_id: str,
1070
+ is_group_admin: bool = False,
981
1071
  ) -> list | None:
982
1072
  """Add a Core Share user to a Core Share group.
983
1073
 
984
1074
  Args:
985
- group_id (str): ID of the Core Share Group
986
- user_id (str): ID of the Core Share User
1075
+ group_id (str):
1076
+ ID of the Core Share group.
1077
+ user_id (str):
1078
+ ID of the Core Share user.
1079
+ is_group_admin (bool, optional):
1080
+ Whether or not the member is a group administrator.
1081
+ Default is False.
987
1082
 
988
1083
  Returns:
989
- list | None: Dictionary with the Core Share group membership or None if the request fails.
1084
+ list | None:
1085
+ Dictionary with the Core Share group membership or None if the request fails.
990
1086
 
991
1087
  Example Response ('errors' is only output if success = False):
992
1088
  [
@@ -1020,6 +1116,7 @@ class CoreShare(object):
1020
1116
  ]
1021
1117
  }
1022
1118
  ]
1119
+
1023
1120
  """
1024
1121
 
1025
1122
  if not self._access_token_admin:
@@ -1033,7 +1130,7 @@ class CoreShare(object):
1033
1130
 
1034
1131
  payload = {"members": [user_email], "specificGroupRole": is_group_admin}
1035
1132
 
1036
- logger.debug(
1133
+ self.logger.debug(
1037
1134
  "Add Core Share user -> '%s' (%s) as %s to Core Share group with ID -> %s; calling -> %s",
1038
1135
  user_email,
1039
1136
  user_id,
@@ -1049,7 +1146,8 @@ class CoreShare(object):
1049
1146
  json_data=payload,
1050
1147
  timeout=REQUEST_TIMEOUT,
1051
1148
  failure_message="Failed to add Core Share user -> '{}' to Core Share group with ID -> {}".format(
1052
- user_email, group_id
1149
+ user_email,
1150
+ group_id,
1053
1151
  ),
1054
1152
  user_credentials=False,
1055
1153
  )
@@ -1057,16 +1155,25 @@ class CoreShare(object):
1057
1155
  # end method definition
1058
1156
 
1059
1157
  def remove_group_member(
1060
- self, group_id: str, user_id: str, is_group_admin: bool = False
1158
+ self,
1159
+ group_id: str,
1160
+ user_id: str,
1161
+ is_group_admin: bool = False,
1061
1162
  ) -> list | None:
1062
1163
  """Remove a Core Share user from a Core Share group.
1063
1164
 
1064
1165
  Args:
1065
- group_id (str): ID of the Core Share Group
1066
- user_id (str): ID of the Core Share User
1166
+ group_id (str):
1167
+ The ID of the Core Share Group.
1168
+ user_id (str):
1169
+ The ID of the Core Share User.
1170
+ is_group_admin (bool, optional):
1171
+ True, if the member is a group admin.
1172
+ Default is False.
1067
1173
 
1068
1174
  Returns:
1069
- list | None: Dictionary with the Core Share group membership or None if the request fails.
1175
+ list | None:
1176
+ Dictionary with the Core Share group membership or None if the request fails.
1070
1177
 
1071
1178
  Example Response ('errors' is only output if success = False):
1072
1179
  [
@@ -1081,6 +1188,7 @@ class CoreShare(object):
1081
1188
  ]
1082
1189
  }
1083
1190
  ]
1191
+
1084
1192
  """
1085
1193
 
1086
1194
  if not self._access_token_admin:
@@ -1094,7 +1202,7 @@ class CoreShare(object):
1094
1202
 
1095
1203
  payload = {"members": [user_email], "specificGroupRole": is_group_admin}
1096
1204
 
1097
- logger.debug(
1205
+ self.logger.debug(
1098
1206
  "Remove Core Share user -> '%s' (%s) as %s from Core Share group with ID -> %s; calling -> %s",
1099
1207
  user_email,
1100
1208
  user_id,
@@ -1110,7 +1218,9 @@ class CoreShare(object):
1110
1218
  json_data=payload,
1111
1219
  timeout=REQUEST_TIMEOUT,
1112
1220
  failure_message="Failed to remove Core Share user -> '{}' ({}) from Core Share group with ID -> {}".format(
1113
- user_email, user_id, group_id
1221
+ user_email,
1222
+ user_id,
1223
+ group_id,
1114
1224
  ),
1115
1225
  user_credentials=False,
1116
1226
  )
@@ -1121,12 +1231,13 @@ class CoreShare(object):
1121
1231
  """Get a Core Share group by its ID.
1122
1232
 
1123
1233
  Args:
1124
- None
1234
+ group_id (str):
1235
+ The ID of the Core Share group.
1125
1236
 
1126
1237
  Returns:
1127
- dict | None: Dictionary with the Core Share group data or None if the request fails.
1238
+ dict | None:
1239
+ Dictionary with the Core Share group data or None if the request fails.
1128
1240
 
1129
- Response example:
1130
1241
  """
1131
1242
 
1132
1243
  if not self._access_token_admin:
@@ -1135,8 +1246,10 @@ class CoreShare(object):
1135
1246
  request_header = self.request_header_admin()
1136
1247
  request_url = self.config()["groupsUrl"] + "/" + group_id
1137
1248
 
1138
- logger.debug(
1139
- "Get Core Share group with ID -> %s; calling -> %s", group_id, request_url
1249
+ self.logger.debug(
1250
+ "Get Core Share group with ID -> %s; calling -> %s",
1251
+ group_id,
1252
+ request_url,
1140
1253
  )
1141
1254
 
1142
1255
  return self.do_request(
@@ -1145,7 +1258,7 @@ class CoreShare(object):
1145
1258
  headers=request_header,
1146
1259
  timeout=REQUEST_TIMEOUT,
1147
1260
  failure_message="Failed to get Core Share group with ID -> {}".format(
1148
- group_id
1261
+ group_id,
1149
1262
  ),
1150
1263
  user_credentials=False,
1151
1264
  )
@@ -1156,10 +1269,12 @@ class CoreShare(object):
1156
1269
  """Get Core Share group by its name.
1157
1270
 
1158
1271
  Args:
1159
- name (str): Name of the group to search.
1272
+ name (str):
1273
+ The name of the group to search.
1160
1274
 
1161
1275
  Returns:
1162
- dict | None: Dictionary with the Core Share group data or None if the request fails.
1276
+ dict | None:
1277
+ Dictionary with the Core Share group data or None if the request fails.
1163
1278
 
1164
1279
  Example result:
1165
1280
  {
@@ -1181,6 +1296,7 @@ class CoreShare(object):
1181
1296
  ],
1182
1297
  'total': 1
1183
1298
  }
1299
+
1184
1300
  """
1185
1301
 
1186
1302
  groups = self.search_groups(
@@ -1192,7 +1308,7 @@ class CoreShare(object):
1192
1308
  # end method definition
1193
1309
 
1194
1310
  def search_groups(self, query_string: str) -> dict | None:
1195
- """Search Core Share group(s) by name.
1311
+ """Search Core Share group(s) using a query string.
1196
1312
 
1197
1313
  Args:
1198
1314
  query_string(str): Query for the group name / property
@@ -1200,7 +1316,6 @@ class CoreShare(object):
1200
1316
  Returns:
1201
1317
  dict | None: Dictionary with the Core Share user data or None if the request fails.
1202
1318
 
1203
- Example response:
1204
1319
  """
1205
1320
 
1206
1321
  if not self._access_token_admin:
@@ -1209,8 +1324,10 @@ class CoreShare(object):
1209
1324
  request_header = self.request_header_admin()
1210
1325
  request_url = self.config()["searchGroupUrl"] + "?q=" + query_string
1211
1326
 
1212
- logger.debug(
1213
- "Search Core Share group by -> %s; calling -> %s", query_string, request_url
1327
+ self.logger.debug(
1328
+ "Search Core Share group by -> %s; calling -> %s",
1329
+ query_string,
1330
+ request_url,
1214
1331
  )
1215
1332
 
1216
1333
  return self.do_request(
@@ -1219,7 +1336,7 @@ class CoreShare(object):
1219
1336
  headers=request_header,
1220
1337
  timeout=REQUEST_TIMEOUT,
1221
1338
  failure_message="Cannot find Core Share group with name / property -> {}".format(
1222
- query_string
1339
+ query_string,
1223
1340
  ),
1224
1341
  user_credentials=False,
1225
1342
  )
@@ -1233,7 +1350,8 @@ class CoreShare(object):
1233
1350
  None
1234
1351
 
1235
1352
  Returns:
1236
- dict | None: Dictionary with the Core Share user data or None if the request fails.
1353
+ dict | None:
1354
+ Dictionary with the Core Share user data or None if the request fails.
1237
1355
 
1238
1356
  Example response (it is a list!):
1239
1357
  [
@@ -1298,6 +1416,7 @@ class CoreShare(object):
1298
1416
  },
1299
1417
  ...
1300
1418
  ]
1419
+
1301
1420
  """
1302
1421
 
1303
1422
  if not self._access_token_admin:
@@ -1306,7 +1425,7 @@ class CoreShare(object):
1306
1425
  request_header = self.request_header_admin()
1307
1426
  request_url = self.config()["usersUrlv1"]
1308
1427
 
1309
- logger.debug("Get Core Share users; calling -> %s", request_url)
1428
+ self.logger.debug("Get Core Share users; calling -> %s", request_url)
1310
1429
 
1311
1430
  return self.do_request(
1312
1431
  url=request_url,
@@ -1323,10 +1442,12 @@ class CoreShare(object):
1323
1442
  """Get a Core Share user by its ID.
1324
1443
 
1325
1444
  Args:
1326
- None
1445
+ user_id (str):
1446
+ The ID of the user.
1327
1447
 
1328
1448
  Returns:
1329
- dict | None: Dictionary with the Core Share user data or None if the request fails.
1449
+ dict | None:
1450
+ Dictionary with the Core Share user data or None if the request fails.
1330
1451
 
1331
1452
  Response example:
1332
1453
  {
@@ -1387,6 +1508,7 @@ class CoreShare(object):
1387
1508
  'quota': 10737418240,
1388
1509
  'usage': 0
1389
1510
  }
1511
+
1390
1512
  """
1391
1513
 
1392
1514
  if not self._access_token_user:
@@ -1395,8 +1517,10 @@ class CoreShare(object):
1395
1517
  request_header = self.request_header_user()
1396
1518
  request_url = self.config()["usersUrlv1"] + "/" + user_id
1397
1519
 
1398
- logger.debug(
1399
- "Get Core Share user with ID -> %s; calling -> %s", user_id, request_url
1520
+ self.logger.debug(
1521
+ "Get Core Share user with ID -> %s; calling -> %s",
1522
+ user_id,
1523
+ request_url,
1400
1524
  )
1401
1525
 
1402
1526
  return self.do_request(
@@ -1405,7 +1529,7 @@ class CoreShare(object):
1405
1529
  headers=request_header,
1406
1530
  timeout=REQUEST_TIMEOUT,
1407
1531
  failure_message="Failed to get Core Share user with ID -> {}".format(
1408
- user_id
1532
+ user_id,
1409
1533
  ),
1410
1534
  user_credentials=True,
1411
1535
  )
@@ -1413,22 +1537,30 @@ class CoreShare(object):
1413
1537
  # end method definition
1414
1538
 
1415
1539
  def get_user_by_name(
1416
- self, first_name: str, last_name: str, user_status: str = "internal-native"
1540
+ self,
1541
+ first_name: str,
1542
+ last_name: str,
1543
+ user_status: str = "internal-native",
1417
1544
  ) -> dict | None:
1418
1545
  """Get Core Share user by its first and last name.
1419
1546
 
1420
1547
  Args:
1421
- first_name (str): First name of the users to search.
1422
- last_name (str): Last name of the users to search.
1423
- user_status (str, optional): type of users. Possible values:
1424
- * internal-enabled
1425
- * internal-pending
1426
- * internal-locked
1427
- * internal-native (non-SSO)
1428
- * internal-sso
1548
+ first_name (str):
1549
+ First name of the users to search.
1550
+ last_name (str):
1551
+ Last name of the users to search.
1552
+ user_status (str, optional):
1553
+ Type of users. Possible values:
1554
+ * internal-enabled
1555
+ * internal-pending
1556
+ * internal-locked
1557
+ * internal-native (non-SSO)
1558
+ * internal-sso
1429
1559
 
1430
1560
  Returns:
1431
- dict | None: Dictionary with the Core Share user data or None if the request fails.
1561
+ dict | None:
1562
+ Dictionary with the Core Share user data or None if the request fails.
1563
+
1432
1564
  """
1433
1565
 
1434
1566
  # Search the users with this first and last name (and hope this is unique ;-).
@@ -1442,21 +1574,27 @@ class CoreShare(object):
1442
1574
  # end method definition
1443
1575
 
1444
1576
  def get_user_by_email(
1445
- self, email: str, user_status: str = "internal-native"
1577
+ self,
1578
+ email: str,
1579
+ user_status: str = "internal-native",
1446
1580
  ) -> dict | None:
1447
1581
  """Get Core Share user by its email address.
1448
1582
 
1449
1583
  Args:
1450
- email (str): Email address of the users to search.
1451
- user_status (str, optional): type of users. Possible values:
1452
- * internal-enabled
1453
- * internal-pending
1454
- * internal-locked
1455
- * internal-native (non-SSO)
1456
- * internal-sso
1584
+ email (str):
1585
+ Email address of the users to search.
1586
+ user_status (str, optional):
1587
+ Type of users. Possible values:
1588
+ * internal-enabled
1589
+ * internal-pending
1590
+ * internal-locked
1591
+ * internal-native (non-SSO)
1592
+ * internal-sso
1457
1593
 
1458
1594
  Returns:
1459
- dict | None: Dictionary with the Core Share user data or None if the request fails.
1595
+ dict | None:
1596
+ Dictionary with the Core Share user data or None if the request fails.
1597
+
1460
1598
  """
1461
1599
 
1462
1600
  # Search the users with this first and last name (and hope this is unique ;-).
@@ -1478,14 +1616,17 @@ class CoreShare(object):
1478
1616
  """Search Core Share user(s) by name / property. Needs to be a Tenant Administrator to do so.
1479
1617
 
1480
1618
  Args:
1481
- query_string (str): string to query the user(s)
1482
- user_status (str, optional): type of users. Possible values:
1483
- * internal-enabled
1484
- * internal-pending
1485
- * internal-locked
1486
- * internal-native (non-SSO)
1487
- * internal-sso
1488
- page_size (int, optional): max number of results per page. We set the default to 100 (Web UI uses 25)
1619
+ query_string (str):
1620
+ The string to query the user(s).
1621
+ user_status (str, optional):
1622
+ The type of users. Possible values:
1623
+ * internal-enabled
1624
+ * internal-pending
1625
+ * internal-locked
1626
+ * internal-native (non-SSO)
1627
+ * internal-sso
1628
+ page_size (int, optional):
1629
+ The maximum number of results per page. We set the default to 100 (Web UI uses 25)
1489
1630
 
1490
1631
  Returns:
1491
1632
  dict | None: Dictionary with the Core Share user data or None if the request fails.
@@ -1524,6 +1665,7 @@ class CoreShare(object):
1524
1665
  ...
1525
1666
  ]
1526
1667
  }
1668
+
1527
1669
  """
1528
1670
 
1529
1671
  if not self._access_token_admin:
@@ -1539,8 +1681,10 @@ class CoreShare(object):
1539
1681
  + str(page_size)
1540
1682
  )
1541
1683
 
1542
- logger.debug(
1543
- "Search Core Share user by -> %s; calling -> %s", query_string, request_url
1684
+ self.logger.debug(
1685
+ "Search Core Share user by -> %s; calling -> %s",
1686
+ query_string,
1687
+ request_url,
1544
1688
  )
1545
1689
 
1546
1690
  return self.do_request(
@@ -1549,7 +1693,7 @@ class CoreShare(object):
1549
1693
  headers=request_header,
1550
1694
  timeout=REQUEST_TIMEOUT,
1551
1695
  failure_message="Failed to search Core Share user with name / property -> {}".format(
1552
- query_string
1696
+ query_string,
1553
1697
  ),
1554
1698
  user_credentials=False,
1555
1699
  )
@@ -1568,15 +1712,22 @@ class CoreShare(object):
1568
1712
  """Add a new Core Share user. This requires a Tenent Admin authorization.
1569
1713
 
1570
1714
  Args:
1571
- first_name (str): First name of the new user
1572
- last_name (str): Last name of the new user
1573
- email (str): Email of the new Core Share user
1574
- password (str | None, optional): Password of the new Core Share user
1575
- title (str | None, optional): Title of the user
1576
- company (str | None, optional): Name of the Company of the user
1715
+ first_name (str):
1716
+ First name of the new user
1717
+ last_name (str):
1718
+ Last name of the new user
1719
+ email (str):
1720
+ Email of the new Core Share user
1721
+ password (str | None, optional):
1722
+ Password of the new Core Share user
1723
+ title (str | None, optional):
1724
+ Title of the user
1725
+ company (str | None, optional):
1726
+ Name of the Company of the user
1577
1727
 
1578
1728
  Returns:
1579
- dict | None: Dictionary with the Core Share User data or None if the request fails.
1729
+ dict | None:
1730
+ Dictionary with the Core Share User data or None if the request fails.
1580
1731
 
1581
1732
  Example response:
1582
1733
  {
@@ -1615,6 +1766,7 @@ class CoreShare(object):
1615
1766
  "quota": 10737418240,
1616
1767
  "usage": 0
1617
1768
  }
1769
+
1618
1770
  """
1619
1771
 
1620
1772
  if not self._access_token_admin:
@@ -1637,7 +1789,7 @@ class CoreShare(object):
1637
1789
  if company:
1638
1790
  payload["company"] = company
1639
1791
 
1640
- logger.debug(
1792
+ self.logger.debug(
1641
1793
  "Adding Core Share user -> %s %s; calling -> %s",
1642
1794
  first_name,
1643
1795
  last_name,
@@ -1651,7 +1803,9 @@ class CoreShare(object):
1651
1803
  json_data=payload,
1652
1804
  timeout=REQUEST_TIMEOUT,
1653
1805
  failure_message="Failed to add Core Share user -> '{} {}' ({})".format(
1654
- first_name, last_name, email
1806
+ first_name,
1807
+ last_name,
1808
+ email,
1655
1809
  ),
1656
1810
  user_credentials=False,
1657
1811
  )
@@ -1662,10 +1816,13 @@ class CoreShare(object):
1662
1816
  """Resend the invite for a Core Share user.
1663
1817
 
1664
1818
  Args:
1665
- user_id (str): The Core Share user ID.
1819
+ user_id (str):
1820
+ The Core Share user ID.
1666
1821
 
1667
1822
  Returns:
1668
- dict: Response from the Core Share API.
1823
+ dict:
1824
+ Response from the Core Share API.
1825
+
1669
1826
  """
1670
1827
 
1671
1828
  if not self._access_token_admin:
@@ -1675,7 +1832,7 @@ class CoreShare(object):
1675
1832
 
1676
1833
  request_url = self.config()["usersUrlv1"] + "/{}".format(user_id)
1677
1834
 
1678
- logger.debug(
1835
+ self.logger.debug(
1679
1836
  "Resend invite for Core Share user with ID -> %s; calling -> %s",
1680
1837
  user_id,
1681
1838
  request_url,
@@ -1690,7 +1847,7 @@ class CoreShare(object):
1690
1847
  json_data=update_data,
1691
1848
  timeout=REQUEST_TIMEOUT,
1692
1849
  failure_message="Failed to resend invite for Core Share user with ID -> {}".format(
1693
- user_id
1850
+ user_id,
1694
1851
  ),
1695
1852
  user_credentials=False,
1696
1853
  )
@@ -1701,10 +1858,15 @@ class CoreShare(object):
1701
1858
  """Update a Core Share user.
1702
1859
 
1703
1860
  Args:
1704
- user_id (str): ID of the Core Share user.
1861
+ user_id (str):
1862
+ The ID of the Core Share user.
1863
+ update_data (dict):
1864
+ The updated user data.
1705
1865
 
1706
1866
  Returns:
1707
- dict: Response or None if the request has failed.
1867
+ dict:
1868
+ REST response or None if the REST call has failed.
1869
+
1708
1870
  """
1709
1871
 
1710
1872
  if not self._access_token_admin:
@@ -1714,15 +1876,15 @@ class CoreShare(object):
1714
1876
 
1715
1877
  request_url = self.config()["usersUrlv1"] + "/{}".format(user_id)
1716
1878
 
1717
- logger.debug(
1879
+ self.logger.debug(
1718
1880
  "Update data of Core Share user with ID -> %s; calling -> %s",
1719
1881
  user_id,
1720
1882
  request_url,
1721
1883
  )
1722
1884
 
1723
- if "email" in update_data and not "password" in update_data:
1724
- logger.warning(
1725
- "Trying to update the email without providing the password. This is likely to fail..."
1885
+ if "email" in update_data and "password" not in update_data:
1886
+ self.logger.warning(
1887
+ "Trying to update the email without providing the password. This is likely to fail...",
1726
1888
  )
1727
1889
 
1728
1890
  return self.do_request(
@@ -1732,7 +1894,7 @@ class CoreShare(object):
1732
1894
  json_data=update_data,
1733
1895
  timeout=REQUEST_TIMEOUT,
1734
1896
  failure_message="Failed to update Core Share user with ID -> {}".format(
1735
- user_id
1897
+ user_id,
1736
1898
  ),
1737
1899
  user_credentials=False,
1738
1900
  )
@@ -1743,13 +1905,17 @@ class CoreShare(object):
1743
1905
  """Add an access role to a Core Share user.
1744
1906
 
1745
1907
  Args:
1746
- user_id (str): The Core Share user ID.
1747
- role_id (int): The role ID:
1748
- * Content Manager = 5
1749
- * Group Admin = 3
1908
+ user_id (str):
1909
+ The Core Share user ID.
1910
+ role_id (int):
1911
+ The role ID:
1912
+ - Content Manager = 5
1913
+ - Group Admin = 3
1750
1914
 
1751
1915
  Returns:
1752
- dict: Response from the Core Share API.
1916
+ dict:
1917
+ Response from the Core Share API.
1918
+
1753
1919
  """
1754
1920
 
1755
1921
  if not self._access_token_admin:
@@ -1757,14 +1923,9 @@ class CoreShare(object):
1757
1923
 
1758
1924
  request_header = self.request_header_admin()
1759
1925
 
1760
- request_url = (
1761
- self.config()["usersUrlv1"]
1762
- + "/{}".format(user_id)
1763
- + "/roles/"
1764
- + str(role_id)
1765
- )
1926
+ request_url = self.config()["usersUrlv1"] + "/{}".format(user_id) + "/roles/" + str(role_id)
1766
1927
 
1767
- logger.debug(
1928
+ self.logger.debug(
1768
1929
  "Add access role -> %s to Core Share user with ID -> %s; calling -> %s",
1769
1930
  str(role_id),
1770
1931
  user_id,
@@ -1777,7 +1938,8 @@ class CoreShare(object):
1777
1938
  headers=request_header,
1778
1939
  timeout=REQUEST_TIMEOUT,
1779
1940
  failure_message="Failed to add access role with ID -> {} to Core Share user with ID -> {}".format(
1780
- role_id, user_id
1941
+ role_id,
1942
+ user_id,
1781
1943
  ),
1782
1944
  user_credentials=False,
1783
1945
  )
@@ -1788,13 +1950,17 @@ class CoreShare(object):
1788
1950
  """Remove an access role from a Core Share user.
1789
1951
 
1790
1952
  Args:
1791
- user_id (str): The Core Share user ID.
1792
- role_id (int): The role ID:
1793
- * Content Manager = 5
1794
- * Group Admin = 3
1953
+ user_id (str):
1954
+ The Core Share user ID.
1955
+ role_id (int):
1956
+ The role ID:
1957
+ * Content Manager = 5
1958
+ * Group Admin = 3
1795
1959
 
1796
1960
  Returns:
1797
- dict: Response from the Core Share API.
1961
+ dict:
1962
+ Response from the Core Share API.
1963
+
1798
1964
  """
1799
1965
 
1800
1966
  if not self._access_token_admin:
@@ -1802,14 +1968,9 @@ class CoreShare(object):
1802
1968
 
1803
1969
  request_header = self.request_header_admin()
1804
1970
 
1805
- request_url = (
1806
- self.config()["usersUrlv1"]
1807
- + "/{}".format(user_id)
1808
- + "/roles/"
1809
- + str(role_id)
1810
- )
1971
+ request_url = self.config()["usersUrlv1"] + "/{}".format(user_id) + "/roles/" + str(role_id)
1811
1972
 
1812
- logger.debug(
1973
+ self.logger.debug(
1813
1974
  "Remove access role with ID -> %s from Core Share user with ID -> %s; calling -> %s",
1814
1975
  str(role_id),
1815
1976
  user_id,
@@ -1822,7 +1983,8 @@ class CoreShare(object):
1822
1983
  headers=request_header,
1823
1984
  timeout=REQUEST_TIMEOUT,
1824
1985
  failure_message="Failed to remove access role with ID -> {} from Core Share user with ID -> {}".format(
1825
- role_id, user_id
1986
+ role_id,
1987
+ user_id,
1826
1988
  ),
1827
1989
  user_credentials=False,
1828
1990
  )
@@ -1839,26 +2001,29 @@ class CoreShare(object):
1839
2001
  """Define the access roles of a Core Share user.
1840
2002
 
1841
2003
  Args:
1842
- user_id (str): ID of the Core Share user
1843
- is_content_manager (bool | None, optional): Assign Content Manager Role if True.
1844
- Removes Content Manager Role if False.
1845
- Does nothing if None.
1846
- Defaults to None.
1847
- is_group_admin (bool | None, optional): Assign Group Admin Role if True.
1848
- Removes Group Admin Role if False.
1849
- Does nothing if None.
1850
- Defaults to None.
1851
- is_admin (bool | None, optional): Makes user Admin if True.
1852
- Removes Admin rights if False.
1853
- Does nothing if None.
1854
- Defaults to None.
2004
+ user_id (str):
2005
+ The ID of the Core Share user.
2006
+ is_content_manager (bool | None, optional):
2007
+ Assign Content Manager Role if True.
2008
+ Removes Content Manager Role if False.
2009
+ Does nothing if None.
2010
+ Defaults to None.
2011
+ is_group_admin (bool | None, optional):
2012
+ Assign Group Admin Role if True.
2013
+ Removes Group Admin Role if False.
2014
+ Does nothing if None.
2015
+ Defaults to None.
2016
+ is_admin (bool | None, optional):
2017
+ Makes user Admin if True.
2018
+ Removes Admin rights if False.
2019
+ Does nothing if None.
2020
+ Defaults to None.
1855
2021
 
1856
2022
  Returns:
1857
- dict: Response from the Core Share API.
1858
- """
2023
+ dict:
2024
+ Response from the Core Share API.
1859
2025
 
1860
- CONTENT_MANAGER_ROLE_ID = 5
1861
- GROUP_ADMIN_ROLE_ID = 3
2026
+ """
1862
2027
 
1863
2028
  response = None
1864
2029
 
@@ -1872,21 +2037,25 @@ class CoreShare(object):
1872
2037
  if is_content_manager is not None:
1873
2038
  if is_content_manager:
1874
2039
  response = self.add_user_access_role(
1875
- user_id=user_id, role_id=CONTENT_MANAGER_ROLE_ID
2040
+ user_id=user_id,
2041
+ role_id=CONTENT_MANAGER_ROLE_ID,
1876
2042
  )
1877
2043
  else:
1878
2044
  response = self.remove_user_access_role(
1879
- user_id=user_id, role_id=CONTENT_MANAGER_ROLE_ID
2045
+ user_id=user_id,
2046
+ role_id=CONTENT_MANAGER_ROLE_ID,
1880
2047
  )
1881
2048
 
1882
2049
  if is_group_admin is not None:
1883
2050
  if is_group_admin:
1884
2051
  response = self.add_user_access_role(
1885
- user_id=user_id, role_id=GROUP_ADMIN_ROLE_ID
2052
+ user_id=user_id,
2053
+ role_id=GROUP_ADMIN_ROLE_ID,
1886
2054
  )
1887
2055
  else:
1888
2056
  response = self.remove_user_access_role(
1889
- user_id=user_id, role_id=GROUP_ADMIN_ROLE_ID
2057
+ user_id=user_id,
2058
+ role_id=GROUP_ADMIN_ROLE_ID,
1890
2059
  )
1891
2060
 
1892
2061
  return response
@@ -1894,17 +2063,25 @@ class CoreShare(object):
1894
2063
  # end method definition
1895
2064
 
1896
2065
  def update_user_password(
1897
- self, user_id: str, password: str, new_password: str
2066
+ self,
2067
+ user_id: str,
2068
+ password: str,
2069
+ new_password: str,
1898
2070
  ) -> dict:
1899
2071
  """Update the password of a Core Share user.
1900
2072
 
1901
2073
  Args:
1902
- user_id (str): The Core Share user ID.
1903
- password (str): Old user password.
1904
- new_password (str): New user password.
2074
+ user_id (str):
2075
+ The Core Share user ID.
2076
+ password (str):
2077
+ The old user password.
2078
+ new_password (str):
2079
+ The new user password.
1905
2080
 
1906
2081
  Returns:
1907
- dict: Response from the Core Share API.
2082
+ dict:
2083
+ Response from the Core Share API.
2084
+
1908
2085
  """
1909
2086
 
1910
2087
  if not self._access_token_admin:
@@ -1914,7 +2091,7 @@ class CoreShare(object):
1914
2091
 
1915
2092
  request_url = self.config()["usersUrlv1"] + "/{}".format(user_id)
1916
2093
 
1917
- logger.debug(
2094
+ self.logger.debug(
1918
2095
  "Update password of Core Share user with ID -> %s; calling -> %s",
1919
2096
  user_id,
1920
2097
  request_url,
@@ -1929,7 +2106,7 @@ class CoreShare(object):
1929
2106
  json_data=update_data,
1930
2107
  timeout=REQUEST_TIMEOUT,
1931
2108
  failure_message="Failed to update password of Core Share user with ID -> {}".format(
1932
- user_id
2109
+ user_id,
1933
2110
  ),
1934
2111
  user_credentials=False,
1935
2112
  )
@@ -1937,15 +2114,25 @@ class CoreShare(object):
1937
2114
  # end method definition
1938
2115
 
1939
2116
  def update_user_photo(
1940
- self, user_id: str, photo_path: str, mime_type: str = "image/jpeg"
2117
+ self,
2118
+ user_id: str,
2119
+ photo_path: str,
2120
+ mime_type: str = "image/jpeg",
1941
2121
  ) -> dict | None:
1942
2122
  """Update the Core Share user photo.
1943
2123
 
1944
2124
  Args:
1945
- user_id (str): Core Share ID of the user
1946
- photo_path (str): file system path with the location of the photo
2125
+ user_id (str):
2126
+ The Core Share user ID.
2127
+ photo_path (str):
2128
+ The file system path with the location of the photo.
2129
+ mime_type (str, optional):
2130
+ The mime type of the photo. Default is "image/jpeg".
2131
+
1947
2132
  Returns:
1948
- dict | None: Dictionary with the Core Share User data or None if the request fails.
2133
+ dict | None:
2134
+ Dictionary with the Core Share User data or None if the request fails.
2135
+
1949
2136
  """
1950
2137
 
1951
2138
  if not self._access_token_user:
@@ -1953,17 +2140,18 @@ class CoreShare(object):
1953
2140
 
1954
2141
  # Check if the photo file exists
1955
2142
  if not os.path.isfile(photo_path):
1956
- logger.error("Photo file -> %s not found!", photo_path)
2143
+ self.logger.error("Photo file -> %s not found!", photo_path)
1957
2144
  return None
1958
2145
 
1959
2146
  try:
1960
2147
  # Read the photo file as binary data
1961
2148
  with open(photo_path, "rb") as image_file:
1962
2149
  photo_data = image_file.read()
1963
- except OSError as exception:
2150
+ except OSError:
1964
2151
  # Handle any errors that occurred while reading the photo file
1965
- logger.error(
1966
- "Error reading photo file -> %s; error -> %s", photo_path, exception
2152
+ self.logger.error(
2153
+ "Error reading photo file -> %s",
2154
+ photo_path,
1967
2155
  )
1968
2156
  return None
1969
2157
 
@@ -1972,7 +2160,7 @@ class CoreShare(object):
1972
2160
  "file": (photo_path, photo_data, mime_type),
1973
2161
  }
1974
2162
 
1975
- logger.debug(
2163
+ self.logger.debug(
1976
2164
  "Update profile photo of Core Share user with ID -> %s; calling -> %s",
1977
2165
  user_id,
1978
2166
  request_url,
@@ -1985,7 +2173,7 @@ class CoreShare(object):
1985
2173
  files=files,
1986
2174
  timeout=REQUEST_TIMEOUT,
1987
2175
  failure_message="Failed to update profile photo of Core Share user with ID -> {}".format(
1988
- user_id
2176
+ user_id,
1989
2177
  ),
1990
2178
  user_credentials=True,
1991
2179
  verify=False,
@@ -1994,13 +2182,17 @@ class CoreShare(object):
1994
2182
  # end method definition
1995
2183
 
1996
2184
  def get_folders(self, parent_id: str) -> list | None:
1997
- """Get Core Share folders under a given parent ID. This runs under user credentials (not admin!)
2185
+ """Get Core Share folders under a given parent ID.
2186
+
2187
+ This runs under user credentials (not admin!)
1998
2188
 
1999
2189
  Args:
2000
- parent_id (str): ID of the parent folder or the rootID of a user
2190
+ parent_id (str):
2191
+ ID of the parent folder or the root ID of a user
2001
2192
 
2002
2193
  Returns:
2003
- list | None: List with the Core Share folders data or None if the request fails.
2194
+ list | None:
2195
+ List with the Core Share folders data or None if the request fails.
2004
2196
 
2005
2197
  Example response (it is a list!):
2006
2198
  [
@@ -2050,10 +2242,11 @@ class CoreShare(object):
2050
2242
  'contentOriginator': {
2051
2243
  'id': '0D949C67-473D-448C-8F4B-B2CCA769F586',
2052
2244
  'name': 'IDEA-TE-QA',
2053
- 'imageUri': '/api/v1/tenants/2595192600759637225/contentOriginator/images/0D949C67-473D-448C-8F4B-B2CCA769F586'
2245
+ 'imageUri': '/api/v1/tenants/2595192600759637225/contentOriginator/images/0D949C67'
2054
2246
  }
2055
2247
  }
2056
2248
  ]
2249
+
2057
2250
  """
2058
2251
 
2059
2252
  if not self._access_token_user:
@@ -2067,7 +2260,7 @@ class CoreShare(object):
2067
2260
  + "?limit=25&order=lastModified:desc&filter=any"
2068
2261
  )
2069
2262
 
2070
- logger.debug(
2263
+ self.logger.debug(
2071
2264
  "Get Core Share folders under parent -> %s; calling -> %s",
2072
2265
  parent_id,
2073
2266
  request_url,
@@ -2079,7 +2272,7 @@ class CoreShare(object):
2079
2272
  headers=request_header,
2080
2273
  timeout=REQUEST_TIMEOUT,
2081
2274
  failure_message="Failed to get Core Share folders under parent -> {}".format(
2082
- parent_id
2275
+ parent_id,
2083
2276
  ),
2084
2277
  user_credentials=True,
2085
2278
  )
@@ -2090,23 +2283,22 @@ class CoreShare(object):
2090
2283
  """Unshare Core Share folder with a given resource ID.
2091
2284
 
2092
2285
  Args:
2093
- resource_id (str): ID of the folder (resource) to unshare with all collaborators
2286
+ resource_id (str):
2287
+ The ID of the folder (resource) to unshare with all collaborators.
2094
2288
 
2095
2289
  Returns:
2096
- dict | None: Dictionary with the Core Share folders data or None if the request fails.
2290
+ dict | None:
2291
+ Dictionary with the Core Share folders data or None if the request fails.
2097
2292
 
2098
- Example response (it is a list!):
2099
2293
  """
2100
2294
 
2101
2295
  if not self._access_token_user:
2102
2296
  self.authenticate_user()
2103
2297
 
2104
2298
  request_header = self.request_header_user()
2105
- request_url = (
2106
- self.config()["foldersUrlv1"] + "/{}".format(resource_id) + "/collaborators"
2107
- )
2299
+ request_url = self.config()["foldersUrlv1"] + "/{}".format(resource_id) + "/collaborators"
2108
2300
 
2109
- logger.debug(
2301
+ self.logger.debug(
2110
2302
  "Unshare Core Share folder -> %s; calling -> %s",
2111
2303
  resource_id,
2112
2304
  request_url,
@@ -2118,7 +2310,7 @@ class CoreShare(object):
2118
2310
  headers=request_header,
2119
2311
  timeout=REQUEST_TIMEOUT,
2120
2312
  failure_message="Failed to unshare Core Share folder with ID -> {}".format(
2121
- resource_id
2313
+ resource_id,
2122
2314
  ),
2123
2315
  user_credentials=True,
2124
2316
  )
@@ -2129,12 +2321,13 @@ class CoreShare(object):
2129
2321
  """Delete Core Share folder with a given resource ID.
2130
2322
 
2131
2323
  Args:
2132
- resource_id (str): ID of the folder (resource) to delete
2324
+ resource_id (str):
2325
+ The ID of the folder (resource) to delete.
2133
2326
 
2134
2327
  Returns:
2135
- dict | None: Dictionary with the Core Share request data or None if the request fails.
2328
+ dict | None:
2329
+ Dictionary with the Core Share request data or None if the request fails.
2136
2330
 
2137
- Example response (it is a list!):
2138
2331
  """
2139
2332
 
2140
2333
  if not self._access_token_user:
@@ -2145,7 +2338,7 @@ class CoreShare(object):
2145
2338
 
2146
2339
  payload = {"state": "deleted"}
2147
2340
 
2148
- logger.debug(
2341
+ self.logger.debug(
2149
2342
  "Delete Core Share folder -> %s; calling -> %s",
2150
2343
  resource_id,
2151
2344
  request_url,
@@ -2158,7 +2351,7 @@ class CoreShare(object):
2158
2351
  data=json.dumps(payload),
2159
2352
  timeout=REQUEST_TIMEOUT,
2160
2353
  failure_message="Failed to delete Core Share folder -> {}".format(
2161
- resource_id
2354
+ resource_id,
2162
2355
  ),
2163
2356
  user_credentials=True,
2164
2357
  )
@@ -2169,12 +2362,13 @@ class CoreShare(object):
2169
2362
  """Delete Core Share document with a given resource ID.
2170
2363
 
2171
2364
  Args:
2172
- resource_id (str): ID of the document (resource) to delete
2365
+ resource_id (str):
2366
+ The ID of the document (resource) to delete.
2173
2367
 
2174
2368
  Returns:
2175
- dict | None: Dictionary with the Core Share request data or None if the request fails.
2369
+ dict | None:
2370
+ Dictionary with the Core Share request data or None if the request fails.
2176
2371
 
2177
- Example response (it is a list!):
2178
2372
  """
2179
2373
 
2180
2374
  if not self._access_token_user:
@@ -2185,7 +2379,7 @@ class CoreShare(object):
2185
2379
 
2186
2380
  payload = {"state": "deleted"}
2187
2381
 
2188
- logger.debug(
2382
+ self.logger.debug(
2189
2383
  "Delete Core Share document -> %s; calling -> %s",
2190
2384
  resource_id,
2191
2385
  request_url,
@@ -2198,7 +2392,7 @@ class CoreShare(object):
2198
2392
  data=json.dumps(payload),
2199
2393
  timeout=REQUEST_TIMEOUT,
2200
2394
  failure_message="Failed to delete Core Share document -> {}".format(
2201
- resource_id
2395
+ resource_id,
2202
2396
  ),
2203
2397
  user_credentials=True,
2204
2398
  )
@@ -2206,14 +2400,18 @@ class CoreShare(object):
2206
2400
  # end method definition
2207
2401
 
2208
2402
  def leave_share(self, user_id: str, resource_id: str) -> dict | None:
2209
- """Remove a Core Share user from a share (i.e. the user leaves the share)
2403
+ """Remove a Core Share user from a share (i.e. the user leaves the share).
2210
2404
 
2211
2405
  Args:
2212
- user_id (str): Core Share ID of the user.
2213
- resource_id (str): Core Share ID of the shared folder.
2406
+ user_id (str):
2407
+ The Core Share user ID.
2408
+ resource_id (str):
2409
+ The Core Share ID of the shared folder.
2214
2410
 
2215
2411
  Returns:
2216
- dict | None: Reponse of the REST call or None in case of an error.
2412
+ dict | None:
2413
+ Reponse of the REST call or None in case of an error.
2414
+
2217
2415
  """
2218
2416
 
2219
2417
  if not self._access_token_user:
@@ -2221,16 +2419,11 @@ class CoreShare(object):
2221
2419
 
2222
2420
  request_header = self.request_header_user()
2223
2421
 
2224
- request_url = (
2225
- self.config()["foldersUrlv1"]
2226
- + "/{}".format(resource_id)
2227
- + "/collaborators/"
2228
- + str(user_id)
2229
- )
2422
+ request_url = self.config()["foldersUrlv1"] + "/{}".format(resource_id) + "/collaborators/" + str(user_id)
2230
2423
 
2231
2424
  payload = {"action": "LEAVE_SHARE"}
2232
2425
 
2233
- logger.debug(
2426
+ self.logger.debug(
2234
2427
  "User with ID -> %s leaves Core Share shared folder with ID -> %s; calling -> %s",
2235
2428
  user_id,
2236
2429
  resource_id,
@@ -2244,7 +2437,8 @@ class CoreShare(object):
2244
2437
  data=json.dumps(payload),
2245
2438
  timeout=REQUEST_TIMEOUT,
2246
2439
  failure_message="User with ID -> {} failed to leave Core Share folder with ID -> {}".format(
2247
- user_id, resource_id
2440
+ user_id,
2441
+ resource_id,
2248
2442
  ),
2249
2443
  user_credentials=True,
2250
2444
  )
@@ -2255,11 +2449,15 @@ class CoreShare(object):
2255
2449
  """Stop of share of a user.
2256
2450
 
2257
2451
  Args:
2258
- user_id (str): Core Share ID of the user.
2259
- resource_id (str): Core Share ID of the shared folder.
2452
+ user_id (str):
2453
+ The Core Share user ID.
2454
+ resource_id (str):
2455
+ The Core Share ID of the shared folder.
2260
2456
 
2261
2457
  Returns:
2262
- dict | None: Response of the REST call or None in case of an error.
2458
+ dict | None:
2459
+ Response of the REST call or None in case of an error.
2460
+
2263
2461
  """
2264
2462
 
2265
2463
  if not self._access_token_user:
@@ -2267,11 +2465,9 @@ class CoreShare(object):
2267
2465
 
2268
2466
  request_header = self.request_header_user()
2269
2467
 
2270
- request_url = (
2271
- self.config()["foldersUrlv1"] + "/{}".format(resource_id) + "/collaborators"
2272
- )
2468
+ request_url = self.config()["foldersUrlv1"] + "/{}".format(resource_id) + "/collaborators"
2273
2469
 
2274
- logger.debug(
2470
+ self.logger.debug(
2275
2471
  "User -> %s stops sharing Core Share shared folder -> %s; calling -> %s",
2276
2472
  user_id,
2277
2473
  resource_id,
@@ -2284,7 +2480,8 @@ class CoreShare(object):
2284
2480
  headers=request_header,
2285
2481
  timeout=REQUEST_TIMEOUT,
2286
2482
  failure_message="User with ID -> {} failed to stop sharing Core Share folder with ID -> {}".format(
2287
- user_id, resource_id
2483
+ user_id,
2484
+ resource_id,
2288
2485
  ),
2289
2486
  user_credentials=True,
2290
2487
  )
@@ -2292,9 +2489,14 @@ class CoreShare(object):
2292
2489
  # end method definition
2293
2490
 
2294
2491
  def cleanup_user_files(
2295
- self, user_id: str, user_login: str, user_password: str
2492
+ self,
2493
+ user_id: str,
2494
+ user_login: str,
2495
+ user_password: str,
2296
2496
  ) -> bool:
2297
- """Cleanup files of a user. This handles different types of resources.
2497
+ """Cleanup files of a user.
2498
+
2499
+ This handles different types of resources.
2298
2500
  * Local resources - not shared
2299
2501
  * Resources shared by the user
2300
2502
  * Resources shared by other users or groups
@@ -2302,12 +2504,17 @@ class CoreShare(object):
2302
2504
  The Core Share admin is not entitled to do this.
2303
2505
 
2304
2506
  Args:
2305
- user_id (str): Core Share ID of the user
2306
- user_login (str): Core Share email (= login) of the user
2307
- user_password (str): Core Share password of the user
2507
+ user_id (str):
2508
+ The Core Share user ID.
2509
+ user_login (str):
2510
+ The Core Share email (= login) of the user.
2511
+ user_password (str):
2512
+ The Core Share password of the user.
2308
2513
 
2309
2514
  Returns:
2310
- bool: True = success, False in case of an error.
2515
+ bool:
2516
+ True = success, False in case of an error.
2517
+
2311
2518
  """
2312
2519
 
2313
2520
  user = self.get_user_by_id(user_id=user_id)
@@ -2316,13 +2523,13 @@ class CoreShare(object):
2316
2523
 
2317
2524
  is_confirmed = self.get_result_value(response=user, key="isConfirmed")
2318
2525
  if not is_confirmed:
2319
- logger.info(
2526
+ self.logger.info(
2320
2527
  "User -> %s is not yet confirmed - so it cannot have files to cleanup.",
2321
2528
  user_id,
2322
2529
  )
2323
2530
  return True
2324
2531
 
2325
- logger.info("Inpersonate as user -> %s to cleanup files...", user_login)
2532
+ self.logger.info("Inpersonate as user -> %s to cleanup files...", user_login)
2326
2533
 
2327
2534
  # Save admin credentials the class has been initialized with:
2328
2535
  admin_credentials = self.credentials()
@@ -2339,24 +2546,25 @@ class CoreShare(object):
2339
2546
  # Get all folders of the user:
2340
2547
  response = self.get_folders(parent_id=user_root_folder_id)
2341
2548
  if not response or not response["results"]:
2342
- logger.info("User -> %s has no items to cleanup!", user_id)
2549
+ self.logger.info("User -> %s has no items to cleanup!", user_id)
2343
2550
  else:
2344
2551
  items = response["results"]
2345
2552
  for item in items:
2346
2553
  if item["isShared"]:
2347
2554
  if item["owner"]["id"] == user_id:
2348
- logger.info(
2555
+ self.logger.info(
2349
2556
  "User -> %s stops sharing item -> %s (%s)...",
2350
2557
  user_id,
2351
2558
  item["name"],
2352
2559
  item["id"],
2353
2560
  )
2354
2561
  response = self.stop_share(
2355
- user_id=user_id, resource_id=item["id"]
2562
+ user_id=user_id,
2563
+ resource_id=item["id"],
2356
2564
  )
2357
2565
  if not response:
2358
2566
  success = False
2359
- logger.info(
2567
+ self.logger.info(
2360
2568
  "User -> %s deletes unshared item -> %s (%s)...",
2361
2569
  user_id,
2362
2570
  item["name"],
@@ -2366,19 +2574,20 @@ class CoreShare(object):
2366
2574
  if not response:
2367
2575
  success = False
2368
2576
  else:
2369
- logger.info(
2577
+ self.logger.info(
2370
2578
  "User -> %s leaves shared folder -> '%s' (%s)...",
2371
2579
  user_id,
2372
2580
  item["name"],
2373
2581
  item["id"],
2374
2582
  )
2375
2583
  response = self.leave_share(
2376
- user_id=user_id, resource_id=item["id"]
2584
+ user_id=user_id,
2585
+ resource_id=item["id"],
2377
2586
  )
2378
2587
  if not response:
2379
2588
  success = False
2380
2589
  else:
2381
- logger.info(
2590
+ self.logger.info(
2382
2591
  "User -> %s deletes local item -> '%s' (%s) of type -> '%s'...",
2383
2592
  user_id,
2384
2593
  item["name"],
@@ -2390,21 +2599,23 @@ class CoreShare(object):
2390
2599
  elif item["resourceType"] == "document":
2391
2600
  response = self.delete_document(item["id"])
2392
2601
  else:
2393
- logger.error(
2394
- "Unsupport resource type -> '%s'", item["resourceType"]
2602
+ self.logger.error(
2603
+ "Unsupport resource type -> '%s'",
2604
+ item["resourceType"],
2395
2605
  )
2396
2606
  response = None
2397
2607
  if not response:
2398
2608
  success = False
2399
2609
 
2400
- logger.info(
2610
+ self.logger.info(
2401
2611
  "End inpersonation and switch back to admin account -> %s...",
2402
2612
  admin_credentials["username"],
2403
2613
  )
2404
2614
 
2405
2615
  # Reset credentials to admin:
2406
2616
  self.set_credentials(
2407
- admin_credentials["username"], admin_credentials["password"]
2617
+ admin_credentials["username"],
2618
+ admin_credentials["password"],
2408
2619
  )
2409
2620
  # Authenticate as administrator the class has been initialized with:
2410
2621
  self.authenticate_user(revalidate=True)
@@ -2417,10 +2628,13 @@ class CoreShare(object):
2417
2628
  """Get (incoming) shares of a Core Share group.
2418
2629
 
2419
2630
  Args:
2420
- group_id (str): Core Share ID of a group
2631
+ group_id (str):
2632
+ The Core Share group ID.
2421
2633
 
2422
2634
  Returns:
2423
- dict | None: Incoming shares or None if the request fails.
2635
+ dict | None:
2636
+ Incoming shares or None if the request fails.
2637
+
2424
2638
  """
2425
2639
 
2426
2640
  if not self._access_token_admin:
@@ -2428,11 +2642,9 @@ class CoreShare(object):
2428
2642
 
2429
2643
  request_header = self.request_header_admin()
2430
2644
 
2431
- request_url = (
2432
- self.config()["groupsUrl"] + "/{}".format(group_id) + "/shares/incoming"
2433
- )
2645
+ request_url = self.config()["groupsUrl"] + "/{}".format(group_id) + "/shares/incoming"
2434
2646
 
2435
- logger.debug(
2647
+ self.logger.debug(
2436
2648
  "Get shares of Core Share group -> %s; calling -> %s",
2437
2649
  group_id,
2438
2650
  request_url,
@@ -2444,7 +2656,7 @@ class CoreShare(object):
2444
2656
  headers=request_header,
2445
2657
  timeout=REQUEST_TIMEOUT,
2446
2658
  failure_message="Failed to get shares of Core Share group -> {}".format(
2447
- group_id
2659
+ group_id,
2448
2660
  ),
2449
2661
  user_credentials=False,
2450
2662
  )
@@ -2455,11 +2667,15 @@ class CoreShare(object):
2455
2667
  """Revoke sharing of a folder with a group.
2456
2668
 
2457
2669
  Args:
2458
- group_id (str): ID of the Core Share group
2459
- resource_id (str): ID of the Core share folder
2670
+ group_id (str):
2671
+ The Core Share group ID.
2672
+ resource_id (str):
2673
+ The ID of the Core share folder.
2460
2674
 
2461
2675
  Returns:
2462
- dict | None: Response or None if the request fails.
2676
+ dict | None:
2677
+ Response or None if the request fails.
2678
+
2463
2679
  """
2464
2680
 
2465
2681
  if not self._access_token_admin:
@@ -2468,13 +2684,10 @@ class CoreShare(object):
2468
2684
  request_header = self.request_header_admin()
2469
2685
 
2470
2686
  request_url = (
2471
- self.config()["foldersUrlv1"]
2472
- + "/{}".format(resource_id)
2473
- + "/collaboratorsAsAdmin/"
2474
- + str(group_id)
2687
+ self.config()["foldersUrlv1"] + "/{}".format(resource_id) + "/collaboratorsAsAdmin/" + str(group_id)
2475
2688
  )
2476
2689
 
2477
- logger.debug(
2690
+ self.logger.debug(
2478
2691
  "Revoke sharing of folder -> %s with group -> %s; calling -> %s",
2479
2692
  resource_id,
2480
2693
  group_id,
@@ -2487,7 +2700,8 @@ class CoreShare(object):
2487
2700
  headers=request_header,
2488
2701
  timeout=REQUEST_TIMEOUT,
2489
2702
  failure_message="Failed to revoke sharing Core Share folder with ID -> {} with group with ID -> {}".format(
2490
- resource_id, group_id
2703
+ resource_id,
2704
+ group_id,
2491
2705
  ),
2492
2706
  user_credentials=False,
2493
2707
  )
@@ -2496,33 +2710,38 @@ class CoreShare(object):
2496
2710
 
2497
2711
  def cleanup_group_shares(self, group_id: str) -> bool:
2498
2712
  """Cleanup all incoming shares of a group.
2499
- The Core Share admin is required to do this.
2713
+
2714
+ The Core Share admin is required to do this.
2500
2715
 
2501
2716
  Args:
2502
- group_id (str): Core Share ID of the group
2717
+ group_id (str):
2718
+ The Core Share group ID.
2503
2719
 
2504
2720
  Returns:
2505
- bool: True = success, False in case of an error.
2721
+ bool:
2722
+ True = success, False in case of an error.
2723
+
2506
2724
  """
2507
2725
 
2508
2726
  response = self.get_group_shares(group_id=group_id)
2509
2727
 
2510
2728
  if not response or not response["shares"]:
2511
- logger.info("Group -> %s has no shares to revoke!", group_id)
2729
+ self.logger.info("Group -> %s has no shares to revoke!", group_id)
2512
2730
  return True
2513
2731
 
2514
2732
  success = True
2515
2733
 
2516
2734
  items = response["shares"]
2517
2735
  for item in items:
2518
- logger.info(
2736
+ self.logger.info(
2519
2737
  "Revoke sharing of folder -> %s (%s) with group -> %s...",
2520
2738
  item["name"],
2521
2739
  item["id"],
2522
2740
  group_id,
2523
2741
  )
2524
2742
  response = self.revoke_group_share(
2525
- group_id=group_id, resource_id=item["id"]
2743
+ group_id=group_id,
2744
+ resource_id=item["id"],
2526
2745
  )
2527
2746
  if not response:
2528
2747
  success = False