pyxecm 3.0.1__py3-none-any.whl → 3.1.1__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.
- pyxecm/avts.py +4 -4
- pyxecm/coreshare.py +14 -15
- pyxecm/helper/data.py +2 -1
- pyxecm/helper/web.py +11 -11
- pyxecm/helper/xml.py +41 -10
- pyxecm/otac.py +1 -1
- pyxecm/otawp.py +19 -19
- pyxecm/otca.py +878 -70
- pyxecm/otcs.py +1716 -349
- pyxecm/otds.py +332 -153
- pyxecm/otkd.py +4 -4
- pyxecm/otmm.py +1 -1
- pyxecm/otpd.py +246 -30
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/METADATA +2 -1
- pyxecm-3.1.1.dist-info/RECORD +82 -0
- pyxecm_api/app.py +45 -35
- pyxecm_api/auth/functions.py +2 -2
- pyxecm_api/auth/router.py +2 -3
- pyxecm_api/common/functions.py +67 -12
- pyxecm_api/settings.py +0 -8
- pyxecm_api/terminal/router.py +1 -1
- pyxecm_api/v1_csai/router.py +33 -18
- pyxecm_customizer/browser_automation.py +161 -79
- pyxecm_customizer/customizer.py +43 -25
- pyxecm_customizer/guidewire.py +422 -8
- pyxecm_customizer/k8s.py +23 -27
- pyxecm_customizer/knowledge_graph.py +498 -20
- pyxecm_customizer/m365.py +45 -44
- pyxecm_customizer/payload.py +1723 -1188
- pyxecm_customizer/payload_list.py +3 -0
- pyxecm_customizer/salesforce.py +122 -79
- pyxecm_customizer/servicenow.py +27 -7
- pyxecm_customizer/settings.py +3 -1
- pyxecm_customizer/successfactors.py +2 -2
- pyxecm_customizer/translate.py +1 -1
- pyxecm-3.0.1.dist-info/RECORD +0 -96
- pyxecm_api/agents/__init__.py +0 -7
- pyxecm_api/agents/app.py +0 -13
- pyxecm_api/agents/functions.py +0 -119
- pyxecm_api/agents/models.py +0 -10
- pyxecm_api/agents/otcm_knowledgegraph/__init__.py +0 -1
- pyxecm_api/agents/otcm_knowledgegraph/functions.py +0 -85
- pyxecm_api/agents/otcm_knowledgegraph/models.py +0 -61
- pyxecm_api/agents/otcm_knowledgegraph/router.py +0 -74
- pyxecm_api/agents/otcm_user_agent/__init__.py +0 -1
- pyxecm_api/agents/otcm_user_agent/models.py +0 -20
- pyxecm_api/agents/otcm_user_agent/router.py +0 -65
- pyxecm_api/agents/otcm_workspace_agent/__init__.py +0 -1
- pyxecm_api/agents/otcm_workspace_agent/models.py +0 -40
- pyxecm_api/agents/otcm_workspace_agent/router.py +0 -200
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/WHEEL +0 -0
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/entry_points.txt +0 -0
pyxecm_customizer/m365.py
CHANGED
|
@@ -32,8 +32,8 @@ request_login_headers = {
|
|
|
32
32
|
"Accept": "application/json",
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
REQUEST_TIMEOUT = 60
|
|
36
|
-
REQUEST_RETRY_DELAY = 20
|
|
35
|
+
REQUEST_TIMEOUT = 60.0
|
|
36
|
+
REQUEST_RETRY_DELAY = 20.0
|
|
37
37
|
REQUEST_MAX_RETRIES = 3
|
|
38
38
|
|
|
39
39
|
|
|
@@ -259,7 +259,7 @@ class M365:
|
|
|
259
259
|
json_data: dict | None = None,
|
|
260
260
|
files: dict | None = None,
|
|
261
261
|
params: dict | None = None,
|
|
262
|
-
timeout:
|
|
262
|
+
timeout: float | None = REQUEST_TIMEOUT,
|
|
263
263
|
show_error: bool = True,
|
|
264
264
|
show_warning: bool = False,
|
|
265
265
|
warning_message: str = "",
|
|
@@ -290,7 +290,7 @@ class M365:
|
|
|
290
290
|
Add key-value pairs to the query string of the URL.
|
|
291
291
|
When you use the params parameter, requests automatically appends
|
|
292
292
|
the key-value pairs to the URL as part of the query string
|
|
293
|
-
timeout (
|
|
293
|
+
timeout (float | None, optional):
|
|
294
294
|
Timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
|
|
295
295
|
show_error (bool, optional):
|
|
296
296
|
Whether or not an error should be logged in case of a failed REST call.
|
|
@@ -418,7 +418,7 @@ class M365:
|
|
|
418
418
|
time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
|
|
419
419
|
else:
|
|
420
420
|
self.logger.error(
|
|
421
|
-
"%s; timeout error
|
|
421
|
+
"%s; timeout error!",
|
|
422
422
|
failure_message,
|
|
423
423
|
)
|
|
424
424
|
if retry_forever:
|
|
@@ -437,7 +437,7 @@ class M365:
|
|
|
437
437
|
time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
|
|
438
438
|
else:
|
|
439
439
|
self.logger.error(
|
|
440
|
-
"%s; connection error
|
|
440
|
+
"%s; connection error!",
|
|
441
441
|
failure_message,
|
|
442
442
|
)
|
|
443
443
|
if retry_forever:
|
|
@@ -512,7 +512,7 @@ class M365:
|
|
|
512
512
|
|
|
513
513
|
def exist_result_item(
|
|
514
514
|
self,
|
|
515
|
-
response: dict,
|
|
515
|
+
response: dict | None,
|
|
516
516
|
key: str,
|
|
517
517
|
value: str,
|
|
518
518
|
sub_dict_name: str = "",
|
|
@@ -520,7 +520,7 @@ class M365:
|
|
|
520
520
|
"""Check existence of key / value pair in the response properties of an MS Graph API call.
|
|
521
521
|
|
|
522
522
|
Args:
|
|
523
|
-
response (dict):
|
|
523
|
+
response (dict | None):
|
|
524
524
|
REST response from an MS Graph REST Call.
|
|
525
525
|
key (str):
|
|
526
526
|
The property name (key).
|
|
@@ -563,7 +563,7 @@ class M365:
|
|
|
563
563
|
|
|
564
564
|
def get_result_value(
|
|
565
565
|
self,
|
|
566
|
-
response: dict,
|
|
566
|
+
response: dict | None,
|
|
567
567
|
key: str,
|
|
568
568
|
index: int = 0,
|
|
569
569
|
sub_dict_name: str = "",
|
|
@@ -571,7 +571,7 @@ class M365:
|
|
|
571
571
|
"""Get value of a result property with a given key of an MS Graph API call.
|
|
572
572
|
|
|
573
573
|
Args:
|
|
574
|
-
response (dict):
|
|
574
|
+
response (dict | None):
|
|
575
575
|
REST response from an MS Graph REST Call.
|
|
576
576
|
key (str):
|
|
577
577
|
The property name (key).
|
|
@@ -584,7 +584,7 @@ class M365:
|
|
|
584
584
|
a case we use the sub_dict_name to access it.
|
|
585
585
|
|
|
586
586
|
Returns:
|
|
587
|
-
str:
|
|
587
|
+
str | None:
|
|
588
588
|
The value for the key, None otherwise.
|
|
589
589
|
|
|
590
590
|
"""
|
|
@@ -678,7 +678,7 @@ class M365:
|
|
|
678
678
|
return None
|
|
679
679
|
else:
|
|
680
680
|
self.logger.error(
|
|
681
|
-
"Result needs to be a list or
|
|
681
|
+
"Result needs to be a list or dictionary but it is of type -> '%s'!",
|
|
682
682
|
str(type(results)),
|
|
683
683
|
)
|
|
684
684
|
return None
|
|
@@ -953,7 +953,7 @@ class M365:
|
|
|
953
953
|
# Some sanity checks:
|
|
954
954
|
if user_email and ("@" not in user_email or "." not in user_email):
|
|
955
955
|
self.logger.error(
|
|
956
|
-
"User email -> %s is not a valid email address",
|
|
956
|
+
"User email -> %s is not a valid email address!",
|
|
957
957
|
user_email,
|
|
958
958
|
)
|
|
959
959
|
return None
|
|
@@ -974,7 +974,7 @@ class M365:
|
|
|
974
974
|
# Construct the email address without the alias
|
|
975
975
|
user_email = user_email[:alias_index] + user_email[domain_index:]
|
|
976
976
|
self.logger.info(
|
|
977
|
-
"M365 user principal name -> %s",
|
|
977
|
+
"M365 user principal name -> '%s'.",
|
|
978
978
|
user_email,
|
|
979
979
|
)
|
|
980
980
|
|
|
@@ -1305,7 +1305,7 @@ class M365:
|
|
|
1305
1305
|
)
|
|
1306
1306
|
else:
|
|
1307
1307
|
self.logger.info(
|
|
1308
|
-
"Photo for M365 user with ID -> %s saved to -> '%s'",
|
|
1308
|
+
"Photo for M365 user with ID -> %s saved to -> '%s'.",
|
|
1309
1309
|
user_id,
|
|
1310
1310
|
file_path,
|
|
1311
1311
|
)
|
|
@@ -1715,7 +1715,7 @@ class M365:
|
|
|
1715
1715
|
group_id = self.get_result_value(response=response, key="id", index=0)
|
|
1716
1716
|
if not group_id:
|
|
1717
1717
|
self.logger.error(
|
|
1718
|
-
"M365 Group -> %s does not exist! Cannot retrieve group members.",
|
|
1718
|
+
"M365 Group -> '%s' does not exist! Cannot retrieve group members.",
|
|
1719
1719
|
group_name,
|
|
1720
1720
|
)
|
|
1721
1721
|
return None
|
|
@@ -1940,9 +1940,9 @@ class M365:
|
|
|
1940
1940
|
headers=request_header,
|
|
1941
1941
|
timeout=REQUEST_TIMEOUT,
|
|
1942
1942
|
)
|
|
1943
|
-
deleted_groups = self.parse_request_response(response)
|
|
1943
|
+
deleted_groups = self.parse_request_response(response) or {}
|
|
1944
1944
|
|
|
1945
|
-
for group in deleted_groups
|
|
1945
|
+
for group in deleted_groups.get("value", []):
|
|
1946
1946
|
group_id = group["id"]
|
|
1947
1947
|
response = self.purge_deleted_item(group_id)
|
|
1948
1948
|
|
|
@@ -1952,9 +1952,9 @@ class M365:
|
|
|
1952
1952
|
headers=request_header,
|
|
1953
1953
|
timeout=REQUEST_TIMEOUT,
|
|
1954
1954
|
)
|
|
1955
|
-
deleted_users = self.parse_request_response(response)
|
|
1955
|
+
deleted_users = self.parse_request_response(response) or {}
|
|
1956
1956
|
|
|
1957
|
-
for user in deleted_users
|
|
1957
|
+
for user in deleted_users.get("value", []):
|
|
1958
1958
|
user_id = user["id"]
|
|
1959
1959
|
response = self.purge_deleted_item(user_id)
|
|
1960
1960
|
|
|
@@ -2012,7 +2012,7 @@ class M365:
|
|
|
2012
2012
|
group_id = self.get_result_value(response=response, key="id", index=0)
|
|
2013
2013
|
if not group_id:
|
|
2014
2014
|
self.logger.error(
|
|
2015
|
-
"M365 Group -> %s not found
|
|
2015
|
+
"M365 Group -> '%s' not found! Cannot check if it has a M365 Team.",
|
|
2016
2016
|
group_name,
|
|
2017
2017
|
)
|
|
2018
2018
|
return False
|
|
@@ -2094,7 +2094,7 @@ class M365:
|
|
|
2094
2094
|
team_id = self.get_result_value(response=response, key="id", index=0)
|
|
2095
2095
|
if not team_id:
|
|
2096
2096
|
self.logger.error(
|
|
2097
|
-
"Failed to get the ID of the M365 Team -> %s via the M365 Group API",
|
|
2097
|
+
"Failed to get the ID of the M365 Team -> '%s' via the M365 Group API!",
|
|
2098
2098
|
name,
|
|
2099
2099
|
)
|
|
2100
2100
|
return None
|
|
@@ -2139,7 +2139,7 @@ class M365:
|
|
|
2139
2139
|
group_id = self.get_result_value(response=response, key="id", index=0)
|
|
2140
2140
|
if not group_id:
|
|
2141
2141
|
self.logger.error(
|
|
2142
|
-
"M365 Group -> '%s' not found
|
|
2142
|
+
"M365 Group -> '%s' not found! It is required for creating a corresponding M365 Team.",
|
|
2143
2143
|
name,
|
|
2144
2144
|
)
|
|
2145
2145
|
return None
|
|
@@ -2258,7 +2258,7 @@ class M365:
|
|
|
2258
2258
|
|
|
2259
2259
|
if not response:
|
|
2260
2260
|
self.logger.error(
|
|
2261
|
-
"Failed to delete M365 Team -> '%s' (%s)",
|
|
2261
|
+
"Failed to delete M365 Team -> '%s' (%s)!",
|
|
2262
2262
|
name,
|
|
2263
2263
|
team_id,
|
|
2264
2264
|
)
|
|
@@ -2266,17 +2266,18 @@ class M365:
|
|
|
2266
2266
|
counter += 1
|
|
2267
2267
|
|
|
2268
2268
|
self.logger.info(
|
|
2269
|
-
"%s M365 Team%s with name -> '%s'
|
|
2269
|
+
"%s M365 Team%s with name -> '%s' %s been deleted.",
|
|
2270
2270
|
str(counter),
|
|
2271
2271
|
"s" if counter > 1 else "",
|
|
2272
2272
|
name,
|
|
2273
|
+
"have" if counter > 1 else "has",
|
|
2273
2274
|
)
|
|
2274
2275
|
return True
|
|
2275
2276
|
else:
|
|
2276
2277
|
self.logger.info("No M365 Team with name -> '%s' found.", name)
|
|
2277
2278
|
return False
|
|
2278
2279
|
else:
|
|
2279
|
-
self.logger.error("Failed to retrieve M365 Teams with name -> '%s'", name)
|
|
2280
|
+
self.logger.error("Failed to retrieve M365 Teams with name -> '%s'!", name)
|
|
2280
2281
|
return False
|
|
2281
2282
|
|
|
2282
2283
|
# end method definition
|
|
@@ -2328,7 +2329,7 @@ class M365:
|
|
|
2328
2329
|
result = re.search(pattern, group_name)
|
|
2329
2330
|
if result:
|
|
2330
2331
|
self.logger.info(
|
|
2331
|
-
"M365 Group name -> '%s' is matching pattern -> '%s'.
|
|
2332
|
+
"M365 Group name -> '%s' is matching pattern -> '%s'. Deleting...",
|
|
2332
2333
|
group_name,
|
|
2333
2334
|
pattern,
|
|
2334
2335
|
)
|
|
@@ -2456,7 +2457,7 @@ class M365:
|
|
|
2456
2457
|
)
|
|
2457
2458
|
if not channel:
|
|
2458
2459
|
self.logger.error(
|
|
2459
|
-
"Cannot find Channel -> %s on M365 Team -> %s",
|
|
2460
|
+
"Cannot find Channel -> '%s' on M365 Team -> '%s'!",
|
|
2460
2461
|
channel_name,
|
|
2461
2462
|
team_name,
|
|
2462
2463
|
)
|
|
@@ -3282,7 +3283,7 @@ class M365:
|
|
|
3282
3283
|
)
|
|
3283
3284
|
if not channel:
|
|
3284
3285
|
self.logger.error(
|
|
3285
|
-
"Cannot find Channel -> '%s' on M365 Team -> '%s'",
|
|
3286
|
+
"Cannot find Channel -> '%s' on M365 Team -> '%s'!",
|
|
3286
3287
|
channel_name,
|
|
3287
3288
|
team_name,
|
|
3288
3289
|
)
|
|
@@ -3375,7 +3376,7 @@ class M365:
|
|
|
3375
3376
|
)
|
|
3376
3377
|
if not channel:
|
|
3377
3378
|
self.logger.error(
|
|
3378
|
-
"Cannot find Channel -> '%s' for M365 Team -> '%s'",
|
|
3379
|
+
"Cannot find Channel -> '%s' for M365 Team -> '%s'!",
|
|
3379
3380
|
channel_name,
|
|
3380
3381
|
team_name,
|
|
3381
3382
|
)
|
|
@@ -3394,7 +3395,7 @@ class M365:
|
|
|
3394
3395
|
)
|
|
3395
3396
|
if not tab:
|
|
3396
3397
|
self.logger.error(
|
|
3397
|
-
"Cannot find Tab -> '%s' on M365 Team -> '%s' (%s) and Channel -> '%s' (%s)",
|
|
3398
|
+
"Cannot find Tab -> '%s' on M365 Team -> '%s' (%s) and Channel -> '%s' (%s)!",
|
|
3398
3399
|
tab_name,
|
|
3399
3400
|
team_name,
|
|
3400
3401
|
team_id,
|
|
@@ -3489,7 +3490,7 @@ class M365:
|
|
|
3489
3490
|
)
|
|
3490
3491
|
if not channel:
|
|
3491
3492
|
self.logger.error(
|
|
3492
|
-
"Cannot find Channel -> '%s' for M365 Team -> '%s'",
|
|
3493
|
+
"Cannot find Channel -> '%s' for M365 Team -> '%s'!",
|
|
3493
3494
|
channel_name,
|
|
3494
3495
|
team_name,
|
|
3495
3496
|
)
|
|
@@ -3506,7 +3507,7 @@ class M365:
|
|
|
3506
3507
|
tab_list = [item for item in response["value"] if item["displayName"] == tab_name]
|
|
3507
3508
|
if not tab_list:
|
|
3508
3509
|
self.logger.error(
|
|
3509
|
-
"Cannot find Tab -> '%s' on M365 Team -> '%s' (%s) and Channel -> '%s' (%s)",
|
|
3510
|
+
"Cannot find Tab -> '%s' on M365 Team -> '%s' (%s) and Channel -> '%s' (%s)!",
|
|
3510
3511
|
tab_name,
|
|
3511
3512
|
team_name,
|
|
3512
3513
|
team_id,
|
|
@@ -4298,7 +4299,7 @@ class M365:
|
|
|
4298
4299
|
)
|
|
4299
4300
|
if not result:
|
|
4300
4301
|
self.logger.error(
|
|
4301
|
-
"Failed to enter password in field -> '%s'",
|
|
4302
|
+
"Failed to enter password in field -> '%s'!",
|
|
4302
4303
|
password_field_id,
|
|
4303
4304
|
)
|
|
4304
4305
|
success = False
|
|
@@ -4313,7 +4314,7 @@ class M365:
|
|
|
4313
4314
|
)
|
|
4314
4315
|
if password_confirm_field:
|
|
4315
4316
|
self.logger.info(
|
|
4316
|
-
"Found password confirmation field on returned page - it seems email verification requests consecutive password
|
|
4317
|
+
"Found password confirmation field on returned page - it seems email verification requests consecutive password.",
|
|
4317
4318
|
)
|
|
4318
4319
|
result = browser_automation_object.find_elem_and_set(
|
|
4319
4320
|
selector=password_confirmation_field_id,
|
|
@@ -4322,7 +4323,7 @@ class M365:
|
|
|
4322
4323
|
)
|
|
4323
4324
|
if not result:
|
|
4324
4325
|
self.logger.error(
|
|
4325
|
-
"Failed to enter password in field -> '%s'",
|
|
4326
|
+
"Failed to enter password in field -> '%s'!",
|
|
4326
4327
|
password_confirmation_field_id,
|
|
4327
4328
|
)
|
|
4328
4329
|
success = False
|
|
@@ -4334,7 +4335,7 @@ class M365:
|
|
|
4334
4335
|
)
|
|
4335
4336
|
if password_submit_button:
|
|
4336
4337
|
self.logger.info(
|
|
4337
|
-
"Submit password change dialog with button -> '%s' (found with XPath -> %s)",
|
|
4338
|
+
"Submit password change dialog with button -> '%s' (found with XPath -> %s).",
|
|
4338
4339
|
password_submit_button.inner_text(),
|
|
4339
4340
|
password_submit_xpath,
|
|
4340
4341
|
)
|
|
@@ -4358,7 +4359,7 @@ class M365:
|
|
|
4358
4359
|
)
|
|
4359
4360
|
if terms_accept_button:
|
|
4360
4361
|
self.logger.info(
|
|
4361
|
-
"Accept terms of service with button -> '%s' (found with XPath -> %s)",
|
|
4362
|
+
"Accept terms of service with button -> '%s' (found with XPath -> %s).",
|
|
4362
4363
|
terms_accept_button.inner_text(),
|
|
4363
4364
|
terms_of_service_xpath,
|
|
4364
4365
|
)
|
|
@@ -4368,7 +4369,7 @@ class M365:
|
|
|
4368
4369
|
)
|
|
4369
4370
|
if not result:
|
|
4370
4371
|
self.logger.error(
|
|
4371
|
-
"Failed to accept terms of service with button -> '%s'",
|
|
4372
|
+
"Failed to accept terms of service with button -> '%s'!",
|
|
4372
4373
|
terms_accept_button.inner_text(),
|
|
4373
4374
|
)
|
|
4374
4375
|
success = False
|
|
@@ -4382,7 +4383,7 @@ class M365:
|
|
|
4382
4383
|
else:
|
|
4383
4384
|
# Salesforce (other than Core Share) is OK with the simple HTTP GET request:
|
|
4384
4385
|
self.logger.info(
|
|
4385
|
-
"Open URL -> %s to verify account or email change",
|
|
4386
|
+
"Open URL -> %s to verify account or email change...",
|
|
4386
4387
|
url,
|
|
4387
4388
|
)
|
|
4388
4389
|
response = self._http_object.http_request(url=url, method="GET")
|
|
@@ -4396,14 +4397,14 @@ class M365:
|
|
|
4396
4397
|
response = self.delete_mail(user_id=m365_user_id, email_id=email_id)
|
|
4397
4398
|
if not response:
|
|
4398
4399
|
self.logger.warning(
|
|
4399
|
-
"Couldn't remove the mail from the inbox of user -> %s",
|
|
4400
|
+
"Couldn't remove the mail from the inbox of user -> %s!",
|
|
4400
4401
|
user_email,
|
|
4401
4402
|
)
|
|
4402
4403
|
# We have success now and can break from the while loop
|
|
4403
4404
|
return True
|
|
4404
4405
|
else:
|
|
4405
4406
|
self.logger.error(
|
|
4406
|
-
"Failed to process e-mail verification for user -> %s",
|
|
4407
|
+
"Failed to process e-mail verification for user -> %s!",
|
|
4407
4408
|
user_email,
|
|
4408
4409
|
)
|
|
4409
4410
|
return False
|
|
@@ -5710,7 +5711,7 @@ class M365:
|
|
|
5710
5711
|
webpart = self.get_sharepoint_webpart(site_id=site_id, page_id=page_id, webpart_id=webpart_id)
|
|
5711
5712
|
if not webpart:
|
|
5712
5713
|
self.logger.error(
|
|
5713
|
-
"Cannot find web part for site ID -> '%s', page -> '%s', webpart ID -> '%s'",
|
|
5714
|
+
"Cannot find web part for site ID -> '%s', page -> '%s', webpart ID -> '%s'!",
|
|
5714
5715
|
site_id,
|
|
5715
5716
|
page_id,
|
|
5716
5717
|
webpart_id,
|
|
@@ -5806,7 +5807,7 @@ class M365:
|
|
|
5806
5807
|
"""
|
|
5807
5808
|
|
|
5808
5809
|
if not user_id and not username:
|
|
5809
|
-
self.logger.error("
|
|
5810
|
+
self.logger.error("No user given to follow SharePoint site. Provide the user ID or its email address!")
|
|
5810
5811
|
return None
|
|
5811
5812
|
|
|
5812
5813
|
user = self.get_user(user_email=username, user_id=user_id)
|