pyxecm 1.4__py3-none-any.whl → 1.5__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/__init__.py +3 -0
- pyxecm/coreshare.py +2636 -0
- pyxecm/customizer/__init__.py +4 -0
- pyxecm/customizer/browser_automation.py +164 -54
- pyxecm/customizer/customizer.py +451 -235
- pyxecm/customizer/k8s.py +6 -6
- pyxecm/customizer/m365.py +1136 -221
- pyxecm/customizer/payload.py +13163 -5844
- pyxecm/customizer/pht.py +503 -0
- pyxecm/customizer/salesforce.py +694 -114
- pyxecm/customizer/sap.py +4 -4
- pyxecm/customizer/servicenow.py +1221 -0
- pyxecm/customizer/successfactors.py +1056 -0
- pyxecm/helper/__init__.py +2 -0
- pyxecm/helper/assoc.py +24 -1
- pyxecm/helper/data.py +1527 -0
- pyxecm/helper/web.py +170 -46
- pyxecm/helper/xml.py +170 -34
- pyxecm/otac.py +309 -23
- pyxecm/otcs.py +2779 -698
- pyxecm/otds.py +347 -108
- pyxecm/otmm.py +808 -0
- pyxecm/otpd.py +13 -10
- {pyxecm-1.4.dist-info → pyxecm-1.5.dist-info}/METADATA +3 -1
- pyxecm-1.5.dist-info/RECORD +30 -0
- {pyxecm-1.4.dist-info → pyxecm-1.5.dist-info}/WHEEL +1 -1
- pyxecm-1.4.dist-info/RECORD +0 -24
- {pyxecm-1.4.dist-info → pyxecm-1.5.dist-info}/LICENSE +0 -0
- {pyxecm-1.4.dist-info → pyxecm-1.5.dist-info}/top_level.txt +0 -0
pyxecm/customizer/salesforce.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Salesforce Module to interact with the Salesforce API
|
|
3
|
+
See: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_rest.htm
|
|
3
4
|
|
|
4
5
|
Class: Salesforce
|
|
5
6
|
Methods:
|
|
@@ -14,15 +15,29 @@ exist_result_item: Check if an dict item is in the response
|
|
|
14
15
|
of the Salesforce API call
|
|
15
16
|
get_result_value: Check if a defined value (based on a key) is in the Salesforce API response
|
|
16
17
|
|
|
17
|
-
authenticate
|
|
18
|
-
|
|
19
|
-
get_user: Get a Salesforce user based on its ID.
|
|
20
|
-
add_user: Add a new Salesforce user.
|
|
18
|
+
authenticate: Authenticates at Salesforce API
|
|
21
19
|
|
|
20
|
+
get_object_id_by_name: Get the ID of a given Salesforce object with a given type and name
|
|
22
21
|
get_object: Get a Salesforce object based on a defined
|
|
23
22
|
field value and return selected result fields.
|
|
24
23
|
add_object: Add object to Salesforce. This is a generic wrapper method
|
|
25
24
|
for the actual add methods.
|
|
25
|
+
|
|
26
|
+
get_group: Get a Salesforce group based on its ID.
|
|
27
|
+
add_group: Add a new Salesforce group.
|
|
28
|
+
update_group: Update a Salesforce group.
|
|
29
|
+
get_group_members: Get Salesforce group members
|
|
30
|
+
add_group_member: Add a user or group to a Salesforce group
|
|
31
|
+
|
|
32
|
+
get_all_user_profiles: Get all user profiles
|
|
33
|
+
get_user_profile_id: Get a user profile ID by profile name
|
|
34
|
+
get_user_id: Get a user ID by user name
|
|
35
|
+
get_user: Get a Salesforce user based on its ID.
|
|
36
|
+
add_user: Add a new Salesforce user.
|
|
37
|
+
update_user: Update a Salesforce user.
|
|
38
|
+
update_user_password: Update the password of a Salesforce user.
|
|
39
|
+
update_user_photo: update the Salesforce user photo.
|
|
40
|
+
|
|
26
41
|
add_account: Add a new Account object to Salesforce.
|
|
27
42
|
add_product: Add a new Product object to Salesforce.
|
|
28
43
|
add_opportunity: Add a new Opportunity object to Salesfoce.
|
|
@@ -38,6 +53,7 @@ __credits__ = ["Kai-Philip Gatzweiler"]
|
|
|
38
53
|
__maintainer__ = "Dr. Marc Diefenbruch"
|
|
39
54
|
__email__ = "mdiefenb@opentext.com"
|
|
40
55
|
|
|
56
|
+
import os
|
|
41
57
|
import json
|
|
42
58
|
import logging
|
|
43
59
|
|
|
@@ -46,12 +62,13 @@ import requests
|
|
|
46
62
|
|
|
47
63
|
logger = logging.getLogger("pyxecm.customizer.salesforce")
|
|
48
64
|
|
|
49
|
-
|
|
65
|
+
REQUEST_LOGIN_HEADERS = {
|
|
50
66
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
51
67
|
"Accept": "application/json",
|
|
52
68
|
}
|
|
53
69
|
|
|
54
70
|
REQUEST_TIMEOUT = 60
|
|
71
|
+
SALESFORCE_API_VERSION = "v60.0"
|
|
55
72
|
|
|
56
73
|
class Salesforce(object):
|
|
57
74
|
"""Used to retrieve and automate stettings in Salesforce."""
|
|
@@ -84,21 +101,56 @@ class Salesforce(object):
|
|
|
84
101
|
security_token (str, optional): security token for Salesforce login
|
|
85
102
|
"""
|
|
86
103
|
|
|
104
|
+
# The instance URL is also returned by the authenticate call
|
|
105
|
+
# but typically it is identical to the base_url.
|
|
106
|
+
self._instance_url = base_url
|
|
107
|
+
|
|
87
108
|
salesforce_config = {}
|
|
88
109
|
|
|
89
|
-
#
|
|
90
|
-
salesforce_config["baseUrl"] = base_url
|
|
110
|
+
# Store the credentials and parameters in a config dictionary:
|
|
91
111
|
salesforce_config["clientId"] = client_id
|
|
92
112
|
salesforce_config["clientSecret"] = client_secret
|
|
93
113
|
salesforce_config["username"] = username
|
|
94
114
|
salesforce_config["password"] = password
|
|
95
115
|
salesforce_config["securityToken"] = security_token
|
|
116
|
+
|
|
117
|
+
# Set the Salesforce URLs and REST API endpoints:
|
|
118
|
+
salesforce_config["baseUrl"] = base_url
|
|
119
|
+
salesforce_config["objectUrl"] = salesforce_config[
|
|
120
|
+
"baseUrl"
|
|
121
|
+
] + "/services/data/{}/sobjects/".format(SALESFORCE_API_VERSION)
|
|
122
|
+
salesforce_config["queryUrl"] = salesforce_config[
|
|
123
|
+
"baseUrl"
|
|
124
|
+
] + "/services/data/{}/query/".format(SALESFORCE_API_VERSION)
|
|
125
|
+
salesforce_config["compositeUrl"] = salesforce_config[
|
|
126
|
+
"baseUrl"
|
|
127
|
+
] + "/services/data/{}/composite/".format(SALESFORCE_API_VERSION)
|
|
128
|
+
salesforce_config["connectUrl"] = salesforce_config[
|
|
129
|
+
"baseUrl"
|
|
130
|
+
] + "/services/data/{}/connect/".format(SALESFORCE_API_VERSION)
|
|
131
|
+
salesforce_config["toolingUrl"] = salesforce_config[
|
|
132
|
+
"baseUrl"
|
|
133
|
+
] + "/services/data/{}/tooling/".format(SALESFORCE_API_VERSION)
|
|
96
134
|
if authorization_url:
|
|
97
135
|
salesforce_config["authenticationUrl"] = authorization_url
|
|
98
136
|
else:
|
|
99
137
|
salesforce_config["authenticationUrl"] = (
|
|
100
138
|
salesforce_config["baseUrl"] + "/services/oauth2/token"
|
|
101
139
|
)
|
|
140
|
+
# URLs that are based on the objectURL (sobjects/):
|
|
141
|
+
salesforce_config["userUrl"] = salesforce_config["objectUrl"] + "User/"
|
|
142
|
+
salesforce_config["groupUrl"] = salesforce_config["objectUrl"] + "Group/"
|
|
143
|
+
salesforce_config["groupMemberUrl"] = (
|
|
144
|
+
salesforce_config["objectUrl"] + "GroupMember/"
|
|
145
|
+
)
|
|
146
|
+
salesforce_config["accountUrl"] = salesforce_config["objectUrl"] + "Account/"
|
|
147
|
+
salesforce_config["productUrl"] = salesforce_config["objectUrl"] + "Product2/"
|
|
148
|
+
salesforce_config["opportunityUrl"] = (
|
|
149
|
+
salesforce_config["objectUrl"] + "Opportunity/"
|
|
150
|
+
)
|
|
151
|
+
salesforce_config["caseUrl"] = salesforce_config["objectUrl"] + "Case/"
|
|
152
|
+
salesforce_config["assetUrl"] = salesforce_config["objectUrl"] + "Asset/"
|
|
153
|
+
salesforce_config["contractUrl"] = salesforce_config["objectUrl"] + "Contract/"
|
|
102
154
|
|
|
103
155
|
# Set the data for the token request
|
|
104
156
|
salesforce_config["authenticationData"] = {
|
|
@@ -111,6 +163,8 @@ class Salesforce(object):
|
|
|
111
163
|
|
|
112
164
|
self._config = salesforce_config
|
|
113
165
|
|
|
166
|
+
# end method definition
|
|
167
|
+
|
|
114
168
|
def config(self) -> dict:
|
|
115
169
|
"""Returns the configuration dictionary
|
|
116
170
|
|
|
@@ -143,8 +197,10 @@ class Salesforce(object):
|
|
|
143
197
|
|
|
144
198
|
request_header = {
|
|
145
199
|
"Authorization": "Bearer {}".format(self._access_token),
|
|
146
|
-
"Content-Type": content_type,
|
|
147
200
|
}
|
|
201
|
+
if content_type:
|
|
202
|
+
request_header["Content-Type"] = content_type
|
|
203
|
+
|
|
148
204
|
return request_header
|
|
149
205
|
|
|
150
206
|
# end method definition
|
|
@@ -278,16 +334,16 @@ class Salesforce(object):
|
|
|
278
334
|
|
|
279
335
|
# Already authenticated and session still valid?
|
|
280
336
|
if self._access_token and not revalidate:
|
|
281
|
-
logger.
|
|
337
|
+
logger.debug(
|
|
282
338
|
"Session still valid - return existing access token -> %s",
|
|
283
339
|
str(self._access_token),
|
|
284
340
|
)
|
|
285
341
|
return self._access_token
|
|
286
342
|
|
|
287
343
|
request_url = self.config()["authenticationUrl"]
|
|
288
|
-
request_header =
|
|
344
|
+
request_header = REQUEST_LOGIN_HEADERS
|
|
289
345
|
|
|
290
|
-
logger.
|
|
346
|
+
logger.debug("Requesting Salesforce Access Token from -> %s", request_url)
|
|
291
347
|
|
|
292
348
|
authenticate_post_body = self.credentials()
|
|
293
349
|
|
|
@@ -346,18 +402,17 @@ class Salesforce(object):
|
|
|
346
402
|
"""
|
|
347
403
|
|
|
348
404
|
if not self._access_token or not self._instance_url:
|
|
349
|
-
|
|
350
|
-
return None
|
|
405
|
+
self.authenticate()
|
|
351
406
|
|
|
352
407
|
request_header = self.request_header()
|
|
353
|
-
request_url =
|
|
408
|
+
request_url = self.config()["queryUrl"]
|
|
354
409
|
|
|
355
410
|
query = f"SELECT Id FROM {object_type} WHERE {name_field} = '{name}'"
|
|
356
411
|
|
|
357
412
|
retries = 0
|
|
358
413
|
while True:
|
|
359
414
|
response = requests.get(
|
|
360
|
-
request_url,
|
|
415
|
+
url=request_url,
|
|
361
416
|
headers=request_header,
|
|
362
417
|
params={"q": query},
|
|
363
418
|
timeout=REQUEST_TIMEOUT,
|
|
@@ -367,13 +422,13 @@ class Salesforce(object):
|
|
|
367
422
|
object_id = self.get_result_value(response, "Id")
|
|
368
423
|
return object_id
|
|
369
424
|
elif response.status_code == 401 and retries == 0:
|
|
370
|
-
logger.
|
|
425
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
371
426
|
self.authenticate(revalidate=True)
|
|
372
427
|
request_header = self.request_header()
|
|
373
428
|
retries += 1
|
|
374
429
|
else:
|
|
375
430
|
logger.error(
|
|
376
|
-
"Failed to get Salesforce object ID for object type -> %s and object name -> %s; status -> %s; error -> %s",
|
|
431
|
+
"Failed to get Salesforce object ID for object type -> '%s' and object name -> '%s'; status -> %s; error -> %s",
|
|
377
432
|
object_type,
|
|
378
433
|
name,
|
|
379
434
|
response.status_code,
|
|
@@ -383,36 +438,6 @@ class Salesforce(object):
|
|
|
383
438
|
|
|
384
439
|
# end method definition
|
|
385
440
|
|
|
386
|
-
def get_profile_id(self, profile_name: str) -> Optional[str]:
|
|
387
|
-
"""Get a user profile ID by profile name.
|
|
388
|
-
|
|
389
|
-
Args:
|
|
390
|
-
profile_name (str): Name of the User Profile.
|
|
391
|
-
|
|
392
|
-
Returns:
|
|
393
|
-
Optional[str]: Technical ID of the user profile.
|
|
394
|
-
"""
|
|
395
|
-
|
|
396
|
-
return self.get_object_id_by_name(object_type="Profile", name=profile_name)
|
|
397
|
-
|
|
398
|
-
# end method definition
|
|
399
|
-
|
|
400
|
-
def get_user_id(self, username: str) -> Optional[str]:
|
|
401
|
-
"""Get a user ID by user name.
|
|
402
|
-
|
|
403
|
-
Args:
|
|
404
|
-
username (str): Name of the User.
|
|
405
|
-
|
|
406
|
-
Returns:
|
|
407
|
-
Optional[str]: Technical ID of the user
|
|
408
|
-
"""
|
|
409
|
-
|
|
410
|
-
return self.get_object_id_by_name(
|
|
411
|
-
object_type="User", name=username, name_field="Username"
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
# end method definition
|
|
415
|
-
|
|
416
441
|
def get_object(
|
|
417
442
|
self,
|
|
418
443
|
object_type: str,
|
|
@@ -433,11 +458,33 @@ class Salesforce(object):
|
|
|
433
458
|
|
|
434
459
|
Returns:
|
|
435
460
|
dict | None: Dictionary with the Salesforce object data.
|
|
461
|
+
|
|
462
|
+
Example response:
|
|
463
|
+
{
|
|
464
|
+
'totalSize': 2,
|
|
465
|
+
'done': True,
|
|
466
|
+
'records': [
|
|
467
|
+
{
|
|
468
|
+
'attributes': {
|
|
469
|
+
'type': 'Opportunity',
|
|
470
|
+
'url': '/services/data/v60.0/sobjects/Opportunity/006Dn00000EclybIAB'
|
|
471
|
+
},
|
|
472
|
+
'Id': '006Dn00000EclybIAB'
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
'attributes': {
|
|
476
|
+
'type': 'Opportunity',
|
|
477
|
+
'url': '/services/data/v60.0/sobjects/Opportunity/006Dn00000EclyfIAB'
|
|
478
|
+
},
|
|
479
|
+
'Id': '006Dn00000EclyfIAB'
|
|
480
|
+
}
|
|
481
|
+
]
|
|
482
|
+
}
|
|
436
483
|
"""
|
|
437
484
|
|
|
438
485
|
if not self._access_token or not self._instance_url:
|
|
439
|
-
|
|
440
|
-
|
|
486
|
+
self.authenticate()
|
|
487
|
+
|
|
441
488
|
if search_field and not search_value:
|
|
442
489
|
logger.error(
|
|
443
490
|
"No search value has been provided for search field -> %s!",
|
|
@@ -445,7 +492,7 @@ class Salesforce(object):
|
|
|
445
492
|
)
|
|
446
493
|
return None
|
|
447
494
|
if not result_fields:
|
|
448
|
-
logger.
|
|
495
|
+
logger.debug(
|
|
449
496
|
"No result fields defined. Using 'FIELDS(STANDARD)' to deliver all standard fields of the object."
|
|
450
497
|
)
|
|
451
498
|
result_fields = ["FIELDS(STANDARD)"]
|
|
@@ -456,19 +503,21 @@ class Salesforce(object):
|
|
|
456
503
|
query += " LIMIT {}".format(str(limit))
|
|
457
504
|
|
|
458
505
|
request_header = self.request_header()
|
|
459
|
-
request_url =
|
|
506
|
+
request_url = self.config()["queryUrl"] + "?q={}".format(query)
|
|
460
507
|
|
|
461
|
-
logger.
|
|
508
|
+
logger.debug(
|
|
462
509
|
"Sending query -> %s to Salesforce; calling -> %s", query, request_url
|
|
463
510
|
)
|
|
464
511
|
|
|
465
512
|
retries = 0
|
|
466
513
|
while True:
|
|
467
|
-
response = requests.get(
|
|
514
|
+
response = requests.get(
|
|
515
|
+
request_url, headers=request_header, timeout=REQUEST_TIMEOUT
|
|
516
|
+
)
|
|
468
517
|
if response.ok:
|
|
469
518
|
return self.parse_request_response(response)
|
|
470
519
|
elif response.status_code == 401 and retries == 0:
|
|
471
|
-
logger.
|
|
520
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
472
521
|
self.authenticate(revalidate=True)
|
|
473
522
|
request_header = self.request_header()
|
|
474
523
|
retries += 1
|
|
@@ -491,9 +540,10 @@ class Salesforce(object):
|
|
|
491
540
|
|
|
492
541
|
Args:
|
|
493
542
|
object_type (str): Type of the Salesforce business object, like "Account" or "Case".
|
|
543
|
+
**kwargs (dict): keyword / value ictionary with additional parameters
|
|
494
544
|
|
|
495
545
|
Returns:
|
|
496
|
-
dict | None: Dictionary with the Salesforce
|
|
546
|
+
dict | None: Dictionary with the Salesforce object data or None if the request fails.
|
|
497
547
|
"""
|
|
498
548
|
|
|
499
549
|
match object_type:
|
|
@@ -568,27 +618,40 @@ class Salesforce(object):
|
|
|
568
618
|
|
|
569
619
|
# end method definition
|
|
570
620
|
|
|
571
|
-
def
|
|
572
|
-
"""Get a
|
|
621
|
+
def get_group_id(self, groupname: str) -> Optional[str]:
|
|
622
|
+
"""Get a group ID by group name.
|
|
573
623
|
|
|
574
624
|
Args:
|
|
575
|
-
|
|
625
|
+
groupname (str): Name of the Group.
|
|
576
626
|
|
|
577
627
|
Returns:
|
|
578
|
-
|
|
628
|
+
Optional[str]: Technical ID of the group
|
|
629
|
+
"""
|
|
630
|
+
|
|
631
|
+
return self.get_object_id_by_name(
|
|
632
|
+
object_type="Group", name=groupname, name_field="Name"
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
# end method definition
|
|
636
|
+
|
|
637
|
+
def get_group(self, group_id: str) -> dict | None:
|
|
638
|
+
"""Get a Salesforce group based on its ID.
|
|
639
|
+
|
|
640
|
+
Args:
|
|
641
|
+
group_id (str): ID of the Salesforce group
|
|
642
|
+
|
|
643
|
+
Returns:
|
|
644
|
+
dict | None: Dictionary with the Salesforce group data or None if the request fails.
|
|
579
645
|
"""
|
|
580
646
|
|
|
581
647
|
if not self._access_token or not self._instance_url:
|
|
582
|
-
|
|
583
|
-
return None
|
|
648
|
+
self.authenticate()
|
|
584
649
|
|
|
585
650
|
request_header = self.request_header()
|
|
586
|
-
request_url = (
|
|
587
|
-
f"{self._instance_url}/services/data/v52.0/sobjects/User/{user_id}"
|
|
588
|
-
)
|
|
651
|
+
request_url = self.config()["groupUrl"] + group_id
|
|
589
652
|
|
|
590
|
-
logger.
|
|
591
|
-
"Get Salesforce
|
|
653
|
+
logger.debug(
|
|
654
|
+
"Get Salesforce group with ID -> %s; calling -> %s", group_id, request_url
|
|
592
655
|
)
|
|
593
656
|
|
|
594
657
|
retries = 0
|
|
@@ -599,14 +662,254 @@ class Salesforce(object):
|
|
|
599
662
|
if response.ok:
|
|
600
663
|
return self.parse_request_response(response)
|
|
601
664
|
elif response.status_code == 401 and retries == 0:
|
|
602
|
-
logger.
|
|
665
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
603
666
|
self.authenticate(revalidate=True)
|
|
604
667
|
request_header = self.request_header()
|
|
605
668
|
retries += 1
|
|
606
669
|
else:
|
|
607
670
|
logger.error(
|
|
608
|
-
"Failed to get Salesforce
|
|
609
|
-
|
|
671
|
+
"Failed to get Salesforce group -> %s; status -> %s; error -> %s",
|
|
672
|
+
group_id,
|
|
673
|
+
response.status_code,
|
|
674
|
+
response.text,
|
|
675
|
+
)
|
|
676
|
+
return None
|
|
677
|
+
|
|
678
|
+
# end method definition
|
|
679
|
+
|
|
680
|
+
def add_group(
|
|
681
|
+
self,
|
|
682
|
+
group_name: str,
|
|
683
|
+
group_type: str = "Regular",
|
|
684
|
+
) -> dict | None:
|
|
685
|
+
"""Add a new Salesforce group.
|
|
686
|
+
|
|
687
|
+
Args:
|
|
688
|
+
group_name (str): Name of the new Salesforce group
|
|
689
|
+
|
|
690
|
+
Returns:
|
|
691
|
+
dict | None: Dictionary with the Salesforce Group data or None if the request fails.
|
|
692
|
+
|
|
693
|
+
Example response:
|
|
694
|
+
{
|
|
695
|
+
'id': '00GDn000000KWE0MAO',
|
|
696
|
+
'success': True,
|
|
697
|
+
'errors': []
|
|
698
|
+
}
|
|
699
|
+
"""
|
|
700
|
+
|
|
701
|
+
if not self._access_token or not self._instance_url:
|
|
702
|
+
self.authenticate()
|
|
703
|
+
|
|
704
|
+
request_header = self.request_header()
|
|
705
|
+
request_url = self.config()["groupUrl"]
|
|
706
|
+
|
|
707
|
+
payload = {"Name": group_name, "Type": group_type}
|
|
708
|
+
|
|
709
|
+
logger.debug(
|
|
710
|
+
"Adding Salesforce group -> %s; calling -> %s", group_name, request_url
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
retries = 0
|
|
714
|
+
while True:
|
|
715
|
+
response = requests.post(
|
|
716
|
+
request_url,
|
|
717
|
+
headers=request_header,
|
|
718
|
+
data=json.dumps(payload),
|
|
719
|
+
timeout=REQUEST_TIMEOUT,
|
|
720
|
+
)
|
|
721
|
+
if response.ok:
|
|
722
|
+
return self.parse_request_response(response)
|
|
723
|
+
elif response.status_code == 401 and retries == 0:
|
|
724
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
725
|
+
self.authenticate(revalidate=True)
|
|
726
|
+
request_header = self.request_header()
|
|
727
|
+
retries += 1
|
|
728
|
+
else:
|
|
729
|
+
logger.error(
|
|
730
|
+
"Failed to add Salesforce group -> %s; status -> %s; error -> %s",
|
|
731
|
+
group_name,
|
|
732
|
+
response.status_code,
|
|
733
|
+
response.text,
|
|
734
|
+
)
|
|
735
|
+
return None
|
|
736
|
+
|
|
737
|
+
# end method definition
|
|
738
|
+
|
|
739
|
+
def update_group(
|
|
740
|
+
self,
|
|
741
|
+
group_id: str,
|
|
742
|
+
update_data: dict,
|
|
743
|
+
) -> dict:
|
|
744
|
+
"""Update a Salesforce group.
|
|
745
|
+
|
|
746
|
+
Args:
|
|
747
|
+
group_id (str): The Salesforce group ID.
|
|
748
|
+
update_data (dict): Dictionary containing the fields to update.
|
|
749
|
+
|
|
750
|
+
Returns:
|
|
751
|
+
dict: Response from the Salesforce API.
|
|
752
|
+
"""
|
|
753
|
+
|
|
754
|
+
if not self._access_token or not self._instance_url:
|
|
755
|
+
self.authenticate()
|
|
756
|
+
|
|
757
|
+
request_header = self.request_header()
|
|
758
|
+
|
|
759
|
+
request_url = self.config()["groupUrl"] + group_id
|
|
760
|
+
|
|
761
|
+
logger.debug(
|
|
762
|
+
"Update Salesforce group with ID -> %s; calling -> %s",
|
|
763
|
+
group_id,
|
|
764
|
+
request_url,
|
|
765
|
+
)
|
|
766
|
+
|
|
767
|
+
retries = 0
|
|
768
|
+
while True:
|
|
769
|
+
response = requests.patch(
|
|
770
|
+
request_url,
|
|
771
|
+
json=update_data,
|
|
772
|
+
headers=request_header,
|
|
773
|
+
timeout=REQUEST_TIMEOUT,
|
|
774
|
+
)
|
|
775
|
+
if response.ok:
|
|
776
|
+
return self.parse_request_response(response)
|
|
777
|
+
elif response.status_code == 401 and retries == 0:
|
|
778
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
779
|
+
self.authenticate(revalidate=True)
|
|
780
|
+
request_header = self.request_header()
|
|
781
|
+
retries += 1
|
|
782
|
+
else:
|
|
783
|
+
logger.error(
|
|
784
|
+
"Failed to update Salesforce group -> %s; status -> %s; error -> %s",
|
|
785
|
+
group_id,
|
|
786
|
+
response.status_code,
|
|
787
|
+
response.text,
|
|
788
|
+
)
|
|
789
|
+
return None
|
|
790
|
+
|
|
791
|
+
# end method definition
|
|
792
|
+
|
|
793
|
+
def get_group_members(self, group_id: str) -> list | None:
|
|
794
|
+
"""Get Salesforce group members
|
|
795
|
+
|
|
796
|
+
Args:
|
|
797
|
+
group_id (str): Id of the group to retrieve the members
|
|
798
|
+
|
|
799
|
+
Returns:
|
|
800
|
+
list | None: result
|
|
801
|
+
|
|
802
|
+
Example response:
|
|
803
|
+
{
|
|
804
|
+
'totalSize': 1,
|
|
805
|
+
'done': True,
|
|
806
|
+
'records': [
|
|
807
|
+
{
|
|
808
|
+
'attributes': {
|
|
809
|
+
'type': 'GroupMember',
|
|
810
|
+
'url': '/services/data/v60.0/sobjects/GroupMember/011Dn000000ELhwIAG'
|
|
811
|
+
},
|
|
812
|
+
'UserOrGroupId': '00GDn000000KWE5MAO'
|
|
813
|
+
}
|
|
814
|
+
]
|
|
815
|
+
}
|
|
816
|
+
"""
|
|
817
|
+
|
|
818
|
+
if not self._access_token or not self._instance_url:
|
|
819
|
+
self.authenticate()
|
|
820
|
+
|
|
821
|
+
request_header = self.request_header()
|
|
822
|
+
|
|
823
|
+
request_url = self.config()["queryUrl"]
|
|
824
|
+
|
|
825
|
+
query = f"SELECT UserOrGroupId FROM GroupMember WHERE GroupId = '{group_id}'"
|
|
826
|
+
params = {"q": query}
|
|
827
|
+
|
|
828
|
+
logger.debug(
|
|
829
|
+
"Get members of Salesforce group with ID -> %s; calling -> %s",
|
|
830
|
+
group_id,
|
|
831
|
+
request_url,
|
|
832
|
+
)
|
|
833
|
+
|
|
834
|
+
retries = 0
|
|
835
|
+
while True:
|
|
836
|
+
response = requests.get(
|
|
837
|
+
request_url,
|
|
838
|
+
headers=request_header,
|
|
839
|
+
params=params,
|
|
840
|
+
timeout=REQUEST_TIMEOUT,
|
|
841
|
+
)
|
|
842
|
+
if response.ok:
|
|
843
|
+
return self.parse_request_response(response)
|
|
844
|
+
elif response.status_code == 401 and retries == 0:
|
|
845
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
846
|
+
self.authenticate(revalidate=True)
|
|
847
|
+
request_header = self.request_header()
|
|
848
|
+
retries += 1
|
|
849
|
+
else:
|
|
850
|
+
logger.error(
|
|
851
|
+
"Failed to retrieve members of Salesforce group with ID -> %s; status -> %s; error -> %s",
|
|
852
|
+
group_id,
|
|
853
|
+
response.status_code,
|
|
854
|
+
response.text,
|
|
855
|
+
)
|
|
856
|
+
return None
|
|
857
|
+
|
|
858
|
+
# end method definition
|
|
859
|
+
|
|
860
|
+
def add_group_member(self, group_id: str, member_id: str) -> dict | None:
|
|
861
|
+
"""Add a user or group to a Salesforce group
|
|
862
|
+
|
|
863
|
+
Args:
|
|
864
|
+
group_id (str): ID of the Salesforce Group to add member to.
|
|
865
|
+
member_id (str): ID of the user or group.
|
|
866
|
+
|
|
867
|
+
Returns:
|
|
868
|
+
dict | None: Dictionary with the Salesforce membership data or None if the request fails.
|
|
869
|
+
|
|
870
|
+
Example response (id is the membership ID):
|
|
871
|
+
{
|
|
872
|
+
'id': '011Dn000000ELhwIAG',
|
|
873
|
+
'success': True,
|
|
874
|
+
'errors': []
|
|
875
|
+
}
|
|
876
|
+
"""
|
|
877
|
+
|
|
878
|
+
if not self._access_token or not self._instance_url:
|
|
879
|
+
self.authenticate()
|
|
880
|
+
|
|
881
|
+
request_url = self.config()["groupMemberUrl"]
|
|
882
|
+
|
|
883
|
+
request_header = self.request_header()
|
|
884
|
+
|
|
885
|
+
payload = {"GroupId": group_id, "UserOrGroupId": member_id}
|
|
886
|
+
|
|
887
|
+
logger.debug(
|
|
888
|
+
"Add member with ID -> %s to Salesforce group with ID -> %s; calling -> %s",
|
|
889
|
+
member_id,
|
|
890
|
+
group_id,
|
|
891
|
+
request_url,
|
|
892
|
+
)
|
|
893
|
+
|
|
894
|
+
retries = 0
|
|
895
|
+
while True:
|
|
896
|
+
response = requests.post(
|
|
897
|
+
request_url,
|
|
898
|
+
headers=request_header,
|
|
899
|
+
json=payload,
|
|
900
|
+
timeout=REQUEST_TIMEOUT,
|
|
901
|
+
)
|
|
902
|
+
if response.ok:
|
|
903
|
+
return self.parse_request_response(response)
|
|
904
|
+
elif response.status_code == 401 and retries == 0:
|
|
905
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
906
|
+
self.authenticate(revalidate=True)
|
|
907
|
+
request_header = self.request_header()
|
|
908
|
+
retries += 1
|
|
909
|
+
else:
|
|
910
|
+
logger.error(
|
|
911
|
+
"Failed to retrieve members of Salesforce group with ID -> %s; status -> %s; error -> %s",
|
|
912
|
+
group_id,
|
|
610
913
|
response.status_code,
|
|
611
914
|
response.text,
|
|
612
915
|
)
|
|
@@ -648,11 +951,10 @@ class Salesforce(object):
|
|
|
648
951
|
"""
|
|
649
952
|
|
|
650
953
|
if not self._access_token or not self._instance_url:
|
|
651
|
-
|
|
652
|
-
return None
|
|
954
|
+
self.authenticate()
|
|
653
955
|
|
|
654
956
|
request_header = self.request_header()
|
|
655
|
-
request_url =
|
|
957
|
+
request_url = self.config()["queryUrl"]
|
|
656
958
|
|
|
657
959
|
query = "SELECT Id, Name, CreatedById, CreatedDate, Description, LastModifiedById, LastModifiedDate, PermissionsCustomizeApplication, PermissionsEditTask, PermissionsImportLeads FROM Profile"
|
|
658
960
|
|
|
@@ -667,7 +969,7 @@ class Salesforce(object):
|
|
|
667
969
|
if response.ok:
|
|
668
970
|
return self.parse_request_response(response)
|
|
669
971
|
elif response.status_code == 401 and retries == 0:
|
|
670
|
-
logger.
|
|
972
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
671
973
|
self.authenticate(revalidate=True)
|
|
672
974
|
request_header = self.request_header()
|
|
673
975
|
retries += 1
|
|
@@ -681,27 +983,112 @@ class Salesforce(object):
|
|
|
681
983
|
|
|
682
984
|
# end method definition
|
|
683
985
|
|
|
986
|
+
def get_user_profile_id(self, profile_name: str) -> Optional[str]:
|
|
987
|
+
"""Get a user profile ID by profile name.
|
|
988
|
+
|
|
989
|
+
Args:
|
|
990
|
+
profile_name (str): Name of the User Profile.
|
|
991
|
+
|
|
992
|
+
Returns:
|
|
993
|
+
Optional[str]: Technical ID of the user profile.
|
|
994
|
+
"""
|
|
995
|
+
|
|
996
|
+
return self.get_object_id_by_name(object_type="Profile", name=profile_name)
|
|
997
|
+
|
|
998
|
+
# end method definition
|
|
999
|
+
|
|
1000
|
+
def get_user_id(self, username: str) -> Optional[str]:
|
|
1001
|
+
"""Get a user ID by user name.
|
|
1002
|
+
|
|
1003
|
+
Args:
|
|
1004
|
+
username (str): Name of the User.
|
|
1005
|
+
|
|
1006
|
+
Returns:
|
|
1007
|
+
Optional[str]: Technical ID of the user
|
|
1008
|
+
"""
|
|
1009
|
+
|
|
1010
|
+
return self.get_object_id_by_name(
|
|
1011
|
+
object_type="User", name=username, name_field="Username"
|
|
1012
|
+
)
|
|
1013
|
+
|
|
1014
|
+
# end method definition
|
|
1015
|
+
|
|
1016
|
+
def get_user(self, user_id: str) -> dict | None:
|
|
1017
|
+
"""Get a Salesforce user based on its ID.
|
|
1018
|
+
|
|
1019
|
+
Args:
|
|
1020
|
+
user_id (str): ID of the Salesforce user
|
|
1021
|
+
|
|
1022
|
+
Returns:
|
|
1023
|
+
dict | None: Dictionary with the Salesforce user data or None if the request fails.
|
|
1024
|
+
"""
|
|
1025
|
+
|
|
1026
|
+
if not self._access_token or not self._instance_url:
|
|
1027
|
+
self.authenticate()
|
|
1028
|
+
|
|
1029
|
+
request_header = self.request_header()
|
|
1030
|
+
request_url = self.config()["userUrl"] + user_id
|
|
1031
|
+
|
|
1032
|
+
logger.debug(
|
|
1033
|
+
"Get Salesforce user with ID -> %s; calling -> %s", user_id, request_url
|
|
1034
|
+
)
|
|
1035
|
+
|
|
1036
|
+
retries = 0
|
|
1037
|
+
while True:
|
|
1038
|
+
response = requests.get(
|
|
1039
|
+
request_url, headers=request_header, timeout=REQUEST_TIMEOUT
|
|
1040
|
+
)
|
|
1041
|
+
if response.ok:
|
|
1042
|
+
return self.parse_request_response(response)
|
|
1043
|
+
elif response.status_code == 401 and retries == 0:
|
|
1044
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
1045
|
+
self.authenticate(revalidate=True)
|
|
1046
|
+
request_header = self.request_header()
|
|
1047
|
+
retries += 1
|
|
1048
|
+
else:
|
|
1049
|
+
logger.error(
|
|
1050
|
+
"Failed to get Salesforce user -> %s; status -> %s; error -> %s",
|
|
1051
|
+
user_id,
|
|
1052
|
+
response.status_code,
|
|
1053
|
+
response.text,
|
|
1054
|
+
)
|
|
1055
|
+
return None
|
|
1056
|
+
|
|
1057
|
+
# end method definition
|
|
1058
|
+
|
|
684
1059
|
def add_user(
|
|
685
1060
|
self,
|
|
686
1061
|
username: str,
|
|
687
1062
|
email: str,
|
|
688
|
-
password: str,
|
|
689
1063
|
firstname: str,
|
|
690
1064
|
lastname: str,
|
|
1065
|
+
title: str | None = None,
|
|
1066
|
+
department: str | None = None,
|
|
1067
|
+
company_name: str = "Innovate",
|
|
1068
|
+
profile_name: Optional[str] = "Standard User",
|
|
691
1069
|
profile_id: Optional[str] = None,
|
|
1070
|
+
time_zone_key: Optional[str] = "America/Los_Angeles",
|
|
1071
|
+
email_encoding_key: Optional[str] = "ISO-8859-1",
|
|
1072
|
+
locale_key: Optional[str] = "en_US",
|
|
692
1073
|
alias: Optional[str] = None,
|
|
693
1074
|
) -> dict | None:
|
|
694
|
-
"""Add a new Salesforce user.
|
|
1075
|
+
"""Add a new Salesforce user. The password has to be set separately.
|
|
695
1076
|
|
|
696
1077
|
Args:
|
|
697
1078
|
username (str): Login name of the new user
|
|
698
1079
|
email (str): Email of the new user
|
|
699
|
-
password (str): Password of the new user
|
|
700
1080
|
firstname (str): First name of the new user.
|
|
701
1081
|
lastname (str): Last name of the new user.
|
|
1082
|
+
title (str): Title of the user.
|
|
1083
|
+
department (str): Department of the user.
|
|
1084
|
+
company_name (str): Name of the Company of the user.
|
|
1085
|
+
profile_name (str): Profile name like "Standard User"
|
|
702
1086
|
profile_id (str, optional): Profile ID of the new user. Defaults to None.
|
|
703
1087
|
Use method get_all_user_profiles() to determine
|
|
704
|
-
the desired Profile for the user.
|
|
1088
|
+
the desired Profile for the user. Or pass the profile_name.
|
|
1089
|
+
time_zone_key (str, optional) in format country/city like "America/Los_Angeles",
|
|
1090
|
+
email_encoding_key (str, optional). Default is "ISO-8859-1".
|
|
1091
|
+
locale_key (str, optional). Default is "en_US".
|
|
705
1092
|
alias (str, optional): Alias of the new user. Defaults to None.
|
|
706
1093
|
|
|
707
1094
|
Returns:
|
|
@@ -709,23 +1096,32 @@ class Salesforce(object):
|
|
|
709
1096
|
"""
|
|
710
1097
|
|
|
711
1098
|
if not self._access_token or not self._instance_url:
|
|
712
|
-
|
|
713
|
-
return None
|
|
1099
|
+
self.authenticate()
|
|
714
1100
|
|
|
715
1101
|
request_header = self.request_header()
|
|
716
|
-
request_url =
|
|
1102
|
+
request_url = self.config()["userUrl"]
|
|
1103
|
+
|
|
1104
|
+
# if just a profile name is given then we determine the profile ID by the name:
|
|
1105
|
+
if profile_name and not profile_id:
|
|
1106
|
+
profile_id = self.get_user_profile_id(profile_name)
|
|
717
1107
|
|
|
718
1108
|
payload = {
|
|
719
1109
|
"Username": username,
|
|
720
1110
|
"Email": email,
|
|
721
|
-
"Password": password,
|
|
722
1111
|
"FirstName": firstname,
|
|
723
1112
|
"LastName": lastname,
|
|
724
1113
|
"ProfileId": profile_id,
|
|
725
|
-
"
|
|
1114
|
+
"Department": department,
|
|
1115
|
+
"CompanyName": company_name,
|
|
1116
|
+
"Title": title,
|
|
1117
|
+
"Alias": alias if alias else username,
|
|
1118
|
+
"TimeZoneSidKey": time_zone_key, # Set default TimeZoneSidKey
|
|
1119
|
+
"LocaleSidKey": locale_key, # Set default LocaleSidKey
|
|
1120
|
+
"EmailEncodingKey": email_encoding_key, # Set default EmailEncodingKey
|
|
1121
|
+
"LanguageLocaleKey": locale_key, # Set default LanguageLocaleKey
|
|
726
1122
|
}
|
|
727
1123
|
|
|
728
|
-
logger.
|
|
1124
|
+
logger.debug(
|
|
729
1125
|
"Adding Salesforce user -> %s; calling -> %s", username, request_url
|
|
730
1126
|
)
|
|
731
1127
|
|
|
@@ -740,7 +1136,7 @@ class Salesforce(object):
|
|
|
740
1136
|
if response.ok:
|
|
741
1137
|
return self.parse_request_response(response)
|
|
742
1138
|
elif response.status_code == 401 and retries == 0:
|
|
743
|
-
logger.
|
|
1139
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
744
1140
|
self.authenticate(revalidate=True)
|
|
745
1141
|
request_header = self.request_header()
|
|
746
1142
|
retries += 1
|
|
@@ -755,6 +1151,193 @@ class Salesforce(object):
|
|
|
755
1151
|
|
|
756
1152
|
# end method definition
|
|
757
1153
|
|
|
1154
|
+
def update_user(
|
|
1155
|
+
self,
|
|
1156
|
+
user_id: str,
|
|
1157
|
+
update_data: dict,
|
|
1158
|
+
) -> dict:
|
|
1159
|
+
"""Update a Salesforce user.
|
|
1160
|
+
|
|
1161
|
+
Args:
|
|
1162
|
+
user_id (str): The Salesforce user ID.
|
|
1163
|
+
update_data (dict): Dictionary containing the fields to update.
|
|
1164
|
+
|
|
1165
|
+
Returns:
|
|
1166
|
+
dict: Response from the Salesforce API.
|
|
1167
|
+
"""
|
|
1168
|
+
|
|
1169
|
+
if not self._access_token or not self._instance_url:
|
|
1170
|
+
self.authenticate()
|
|
1171
|
+
|
|
1172
|
+
request_header = self.request_header()
|
|
1173
|
+
|
|
1174
|
+
request_url = self.config()["userUrl"] + user_id
|
|
1175
|
+
|
|
1176
|
+
logger.debug(
|
|
1177
|
+
"Update Salesforce user with ID -> %s; calling -> %s", user_id, request_url
|
|
1178
|
+
)
|
|
1179
|
+
|
|
1180
|
+
retries = 0
|
|
1181
|
+
while True:
|
|
1182
|
+
response = requests.patch(
|
|
1183
|
+
request_url,
|
|
1184
|
+
json=update_data,
|
|
1185
|
+
headers=request_header,
|
|
1186
|
+
timeout=REQUEST_TIMEOUT,
|
|
1187
|
+
)
|
|
1188
|
+
if response.ok:
|
|
1189
|
+
return self.parse_request_response(response)
|
|
1190
|
+
elif response.status_code == 401 and retries == 0:
|
|
1191
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
1192
|
+
self.authenticate(revalidate=True)
|
|
1193
|
+
request_header = self.request_header()
|
|
1194
|
+
retries += 1
|
|
1195
|
+
else:
|
|
1196
|
+
logger.error(
|
|
1197
|
+
"Failed to update Salesforce user -> %s; status -> %s; error -> %s",
|
|
1198
|
+
user_id,
|
|
1199
|
+
response.status_code,
|
|
1200
|
+
response.text,
|
|
1201
|
+
)
|
|
1202
|
+
return None
|
|
1203
|
+
|
|
1204
|
+
# end method definition
|
|
1205
|
+
|
|
1206
|
+
def update_user_password(
|
|
1207
|
+
self,
|
|
1208
|
+
user_id: str,
|
|
1209
|
+
password: str,
|
|
1210
|
+
) -> dict:
|
|
1211
|
+
"""Update the password of a Salesforce user.
|
|
1212
|
+
|
|
1213
|
+
Args:
|
|
1214
|
+
user_id (str): The Salesforce user ID.
|
|
1215
|
+
password (str): New user password.
|
|
1216
|
+
|
|
1217
|
+
Returns:
|
|
1218
|
+
dict: Response from the Salesforce API.
|
|
1219
|
+
"""
|
|
1220
|
+
|
|
1221
|
+
if not self._access_token or not self._instance_url:
|
|
1222
|
+
self.authenticate()
|
|
1223
|
+
|
|
1224
|
+
request_header = self.request_header()
|
|
1225
|
+
|
|
1226
|
+
request_url = self.config()["userUrl"] + "{}/password".format(user_id)
|
|
1227
|
+
|
|
1228
|
+
logger.debug(
|
|
1229
|
+
"Update password of Salesforce user with ID -> %s; calling -> %s",
|
|
1230
|
+
user_id,
|
|
1231
|
+
request_url,
|
|
1232
|
+
)
|
|
1233
|
+
|
|
1234
|
+
update_data = {"NewPassword": password}
|
|
1235
|
+
|
|
1236
|
+
retries = 0
|
|
1237
|
+
while True:
|
|
1238
|
+
response = requests.post(
|
|
1239
|
+
request_url,
|
|
1240
|
+
json=update_data,
|
|
1241
|
+
headers=request_header,
|
|
1242
|
+
timeout=REQUEST_TIMEOUT,
|
|
1243
|
+
)
|
|
1244
|
+
if response.ok:
|
|
1245
|
+
return self.parse_request_response(response)
|
|
1246
|
+
elif response.status_code == 401 and retries == 0:
|
|
1247
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
1248
|
+
self.authenticate(revalidate=True)
|
|
1249
|
+
request_header = self.request_header()
|
|
1250
|
+
retries += 1
|
|
1251
|
+
else:
|
|
1252
|
+
logger.error(
|
|
1253
|
+
"Failed to update password of Salesforce user -> %s; status -> %s; error -> %s",
|
|
1254
|
+
user_id,
|
|
1255
|
+
response.status_code,
|
|
1256
|
+
response.text,
|
|
1257
|
+
)
|
|
1258
|
+
return None
|
|
1259
|
+
|
|
1260
|
+
# end method definition
|
|
1261
|
+
|
|
1262
|
+
def update_user_photo(
|
|
1263
|
+
self,
|
|
1264
|
+
user_id: str,
|
|
1265
|
+
photo_path: str,
|
|
1266
|
+
) -> dict | None:
|
|
1267
|
+
"""Update the Salesforce user photo.
|
|
1268
|
+
|
|
1269
|
+
Args:
|
|
1270
|
+
user_id (str): Salesforce ID of the user
|
|
1271
|
+
photo_path (str): file system path with the location of the photo
|
|
1272
|
+
Returns:
|
|
1273
|
+
dict | None: Dictionary with the Salesforce User data or None if the request fails.
|
|
1274
|
+
"""
|
|
1275
|
+
|
|
1276
|
+
if not self._access_token or not self._instance_url:
|
|
1277
|
+
self.authenticate()
|
|
1278
|
+
|
|
1279
|
+
# Check if the photo file exists
|
|
1280
|
+
if not os.path.isfile(photo_path):
|
|
1281
|
+
logger.error("Photo file -> %s not found!", photo_path)
|
|
1282
|
+
return None
|
|
1283
|
+
|
|
1284
|
+
try:
|
|
1285
|
+
# Read the photo file as binary data
|
|
1286
|
+
with open(photo_path, "rb") as image_file:
|
|
1287
|
+
photo_data = image_file.read()
|
|
1288
|
+
except OSError as exception:
|
|
1289
|
+
# Handle any errors that occurred while reading the photo file
|
|
1290
|
+
logger.error(
|
|
1291
|
+
"Error reading photo file -> %s; error -> %s", photo_path, exception
|
|
1292
|
+
)
|
|
1293
|
+
return None
|
|
1294
|
+
|
|
1295
|
+
request_header = self.request_header(content_type=None)
|
|
1296
|
+
|
|
1297
|
+
data = {"json": json.dumps({"cropX": 0, "cropY": 0, "cropSize": 200})}
|
|
1298
|
+
request_url = self.config()["connectUrl"] + f"user-profiles/{user_id}/photo"
|
|
1299
|
+
files = {
|
|
1300
|
+
"fileUpload": (
|
|
1301
|
+
photo_path,
|
|
1302
|
+
photo_data,
|
|
1303
|
+
"application/octet-stream",
|
|
1304
|
+
)
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
logger.debug(
|
|
1308
|
+
"Update profile photo of Salesforce user with ID -> %s; calling -> %s",
|
|
1309
|
+
user_id,
|
|
1310
|
+
request_url,
|
|
1311
|
+
)
|
|
1312
|
+
|
|
1313
|
+
retries = 0
|
|
1314
|
+
while True:
|
|
1315
|
+
response = requests.post(
|
|
1316
|
+
request_url,
|
|
1317
|
+
files=files,
|
|
1318
|
+
data=data,
|
|
1319
|
+
headers=request_header,
|
|
1320
|
+
verify=False,
|
|
1321
|
+
timeout=REQUEST_TIMEOUT,
|
|
1322
|
+
)
|
|
1323
|
+
if response.ok:
|
|
1324
|
+
return self.parse_request_response(response)
|
|
1325
|
+
elif response.status_code == 401 and retries == 0:
|
|
1326
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
1327
|
+
self.authenticate(revalidate=True)
|
|
1328
|
+
request_header = self.request_header()
|
|
1329
|
+
retries += 1
|
|
1330
|
+
else:
|
|
1331
|
+
logger.error(
|
|
1332
|
+
"Failed to update profile photo of Salesforce user with ID -> %s; status -> %s; error -> %s",
|
|
1333
|
+
user_id,
|
|
1334
|
+
response.status_code,
|
|
1335
|
+
response.text,
|
|
1336
|
+
)
|
|
1337
|
+
return None
|
|
1338
|
+
|
|
1339
|
+
# end method definition
|
|
1340
|
+
|
|
758
1341
|
def add_account(
|
|
759
1342
|
self,
|
|
760
1343
|
account_name: str,
|
|
@@ -783,11 +1366,10 @@ class Salesforce(object):
|
|
|
783
1366
|
"""
|
|
784
1367
|
|
|
785
1368
|
if not self._access_token or not self._instance_url:
|
|
786
|
-
|
|
787
|
-
return None
|
|
1369
|
+
self.authenticate()
|
|
788
1370
|
|
|
789
1371
|
request_header = self.request_header()
|
|
790
|
-
request_url =
|
|
1372
|
+
request_url = self.config()["accountUrl"]
|
|
791
1373
|
|
|
792
1374
|
payload = {
|
|
793
1375
|
"Name": account_name,
|
|
@@ -800,7 +1382,7 @@ class Salesforce(object):
|
|
|
800
1382
|
}
|
|
801
1383
|
payload.update(kwargs) # Add additional fields from kwargs
|
|
802
1384
|
|
|
803
|
-
logger.
|
|
1385
|
+
logger.debug(
|
|
804
1386
|
"Adding Salesforce account -> %s; calling -> %s", account_name, request_url
|
|
805
1387
|
)
|
|
806
1388
|
|
|
@@ -815,7 +1397,7 @@ class Salesforce(object):
|
|
|
815
1397
|
if response.ok:
|
|
816
1398
|
return self.parse_request_response(response)
|
|
817
1399
|
elif response.status_code == 401 and retries == 0:
|
|
818
|
-
logger.
|
|
1400
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
819
1401
|
self.authenticate(revalidate=True)
|
|
820
1402
|
request_header = self.request_header()
|
|
821
1403
|
retries += 1
|
|
@@ -851,11 +1433,10 @@ class Salesforce(object):
|
|
|
851
1433
|
"""
|
|
852
1434
|
|
|
853
1435
|
if not self._access_token or not self._instance_url:
|
|
854
|
-
|
|
855
|
-
return None
|
|
1436
|
+
self.authenticate()
|
|
856
1437
|
|
|
857
1438
|
request_header = self.request_header()
|
|
858
|
-
request_url =
|
|
1439
|
+
request_url = self.config()["productUrl"]
|
|
859
1440
|
|
|
860
1441
|
payload = {
|
|
861
1442
|
"Name": product_name,
|
|
@@ -865,7 +1446,7 @@ class Salesforce(object):
|
|
|
865
1446
|
}
|
|
866
1447
|
payload.update(kwargs) # Add additional fields from kwargs
|
|
867
1448
|
|
|
868
|
-
logger.
|
|
1449
|
+
logger.debug(
|
|
869
1450
|
"Add Salesforce product -> %s; calling -> %s", product_name, request_url
|
|
870
1451
|
)
|
|
871
1452
|
|
|
@@ -880,7 +1461,7 @@ class Salesforce(object):
|
|
|
880
1461
|
if response.ok:
|
|
881
1462
|
return self.parse_request_response(response)
|
|
882
1463
|
elif response.status_code == 401 and retries == 0:
|
|
883
|
-
logger.
|
|
1464
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
884
1465
|
self.authenticate(revalidate=True)
|
|
885
1466
|
request_header = self.request_header()
|
|
886
1467
|
retries += 1
|
|
@@ -922,11 +1503,10 @@ class Salesforce(object):
|
|
|
922
1503
|
"""
|
|
923
1504
|
|
|
924
1505
|
if not self._access_token or not self._instance_url:
|
|
925
|
-
|
|
926
|
-
return None
|
|
1506
|
+
self.authenticate()
|
|
927
1507
|
|
|
928
1508
|
request_header = self.request_header()
|
|
929
|
-
request_url =
|
|
1509
|
+
request_url = self.config()["opportunityUrl"]
|
|
930
1510
|
|
|
931
1511
|
payload = {
|
|
932
1512
|
"Name": name,
|
|
@@ -939,7 +1519,7 @@ class Salesforce(object):
|
|
|
939
1519
|
payload["Description"] = description
|
|
940
1520
|
payload.update(kwargs) # Add additional fields from kwargs
|
|
941
1521
|
|
|
942
|
-
logger.
|
|
1522
|
+
logger.debug(
|
|
943
1523
|
"Add Salesforce opportunity -> %s; calling -> %s", name, request_url
|
|
944
1524
|
)
|
|
945
1525
|
|
|
@@ -954,7 +1534,7 @@ class Salesforce(object):
|
|
|
954
1534
|
if response.ok:
|
|
955
1535
|
return self.parse_request_response(response)
|
|
956
1536
|
elif response.status_code == 401 and retries == 0:
|
|
957
|
-
logger.
|
|
1537
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
958
1538
|
self.authenticate(revalidate=True)
|
|
959
1539
|
request_header = self.request_header()
|
|
960
1540
|
retries += 1
|
|
@@ -967,6 +1547,8 @@ class Salesforce(object):
|
|
|
967
1547
|
)
|
|
968
1548
|
return None
|
|
969
1549
|
|
|
1550
|
+
# end method definition
|
|
1551
|
+
|
|
970
1552
|
def add_case(
|
|
971
1553
|
self,
|
|
972
1554
|
subject: str,
|
|
@@ -990,6 +1572,7 @@ class Salesforce(object):
|
|
|
990
1572
|
priority (str): Priority of the case. Typical values: "High", "Medium", "Low".
|
|
991
1573
|
origin (str): origin (source) of the case. Typical values: "Email", "Phone", "Web"
|
|
992
1574
|
account_id (str): technical ID of the related Account
|
|
1575
|
+
owner_id (str): owner of the case
|
|
993
1576
|
asset_id (str): technical ID of the related Asset
|
|
994
1577
|
product_id (str): technical ID of the related Product
|
|
995
1578
|
kwargs (Any): additional values (e.g. custom fields)
|
|
@@ -999,11 +1582,10 @@ class Salesforce(object):
|
|
|
999
1582
|
"""
|
|
1000
1583
|
|
|
1001
1584
|
if not self._access_token or not self._instance_url:
|
|
1002
|
-
|
|
1003
|
-
return None
|
|
1585
|
+
self.authenticate()
|
|
1004
1586
|
|
|
1005
1587
|
request_header = self.request_header()
|
|
1006
|
-
request_url =
|
|
1588
|
+
request_url = self.config()["caseUrl"]
|
|
1007
1589
|
|
|
1008
1590
|
payload = {
|
|
1009
1591
|
"Subject": subject,
|
|
@@ -1021,7 +1603,7 @@ class Salesforce(object):
|
|
|
1021
1603
|
payload["ProductId"] = product_id
|
|
1022
1604
|
payload.update(kwargs) # Add additional fields from kwargs
|
|
1023
1605
|
|
|
1024
|
-
logger.
|
|
1606
|
+
logger.debug("Add Salesforce case -> %s; calling -> %s", subject, request_url)
|
|
1025
1607
|
|
|
1026
1608
|
retries = 0
|
|
1027
1609
|
while True:
|
|
@@ -1034,7 +1616,7 @@ class Salesforce(object):
|
|
|
1034
1616
|
if response.ok:
|
|
1035
1617
|
return self.parse_request_response(response)
|
|
1036
1618
|
elif response.status_code == 401 and retries == 0:
|
|
1037
|
-
logger.
|
|
1619
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
1038
1620
|
self.authenticate(revalidate=True)
|
|
1039
1621
|
request_header = self.request_header()
|
|
1040
1622
|
retries += 1
|
|
@@ -1077,11 +1659,10 @@ class Salesforce(object):
|
|
|
1077
1659
|
"""
|
|
1078
1660
|
|
|
1079
1661
|
if not self._access_token or not self._instance_url:
|
|
1080
|
-
|
|
1081
|
-
return None
|
|
1662
|
+
self.authenticate()
|
|
1082
1663
|
|
|
1083
1664
|
request_header = self.request_header()
|
|
1084
|
-
request_url =
|
|
1665
|
+
request_url = self.config()["assetUrl"]
|
|
1085
1666
|
|
|
1086
1667
|
payload = {
|
|
1087
1668
|
"Name": asset_name,
|
|
@@ -1095,7 +1676,7 @@ class Salesforce(object):
|
|
|
1095
1676
|
payload["Description"] = description
|
|
1096
1677
|
payload.update(kwargs) # Add additional fields from kwargs
|
|
1097
1678
|
|
|
1098
|
-
logger.
|
|
1679
|
+
logger.debug(
|
|
1099
1680
|
"Add Salesforce asset -> %s; calling -> %s", asset_name, request_url
|
|
1100
1681
|
)
|
|
1101
1682
|
|
|
@@ -1110,7 +1691,7 @@ class Salesforce(object):
|
|
|
1110
1691
|
if response.ok:
|
|
1111
1692
|
return self.parse_request_response(response)
|
|
1112
1693
|
elif response.status_code == 401 and retries == 0:
|
|
1113
|
-
logger.
|
|
1694
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
1114
1695
|
self.authenticate(revalidate=True)
|
|
1115
1696
|
request_header = self.request_header()
|
|
1116
1697
|
retries += 1
|
|
@@ -1151,11 +1732,10 @@ class Salesforce(object):
|
|
|
1151
1732
|
"""
|
|
1152
1733
|
|
|
1153
1734
|
if not self._access_token or not self._instance_url:
|
|
1154
|
-
|
|
1155
|
-
return None
|
|
1735
|
+
self.authenticate()
|
|
1156
1736
|
|
|
1157
1737
|
request_header = self.request_header()
|
|
1158
|
-
request_url =
|
|
1738
|
+
request_url = self.config()["contractUrl"]
|
|
1159
1739
|
|
|
1160
1740
|
payload = {
|
|
1161
1741
|
"AccountId": account_id,
|
|
@@ -1169,7 +1749,7 @@ class Salesforce(object):
|
|
|
1169
1749
|
payload["ContractType"] = contract_type
|
|
1170
1750
|
payload.update(kwargs) # Add additional fields from kwargs
|
|
1171
1751
|
|
|
1172
|
-
logger.
|
|
1752
|
+
logger.debug(
|
|
1173
1753
|
"Adding Salesforce contract for account ID -> %s; calling -> %s",
|
|
1174
1754
|
account_id,
|
|
1175
1755
|
request_url,
|
|
@@ -1186,7 +1766,7 @@ class Salesforce(object):
|
|
|
1186
1766
|
if response.ok:
|
|
1187
1767
|
return self.parse_request_response(response)
|
|
1188
1768
|
elif response.status_code == 401 and retries == 0:
|
|
1189
|
-
logger.
|
|
1769
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
1190
1770
|
self.authenticate(revalidate=True)
|
|
1191
1771
|
request_header = self.request_header()
|
|
1192
1772
|
retries += 1
|