pyxecm 1.5__py3-none-any.whl → 1.6__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.

@@ -8,7 +8,9 @@ Methods:
8
8
  __init__ : class initializer
9
9
  config : Returns config data set
10
10
  credentials: Returns the token data
11
+
11
12
  request_header: Returns the request header for Salesforce API calls
13
+ do_request: Call an Salesforce REST API in a safe way
12
14
  parse_request_response: Parse the REST API responses and convert
13
15
  them to Python dict in a safe way
14
16
  exist_result_item: Check if an dict item is in the response
@@ -56,8 +58,11 @@ __email__ = "mdiefenb@opentext.com"
56
58
  import os
57
59
  import json
58
60
  import logging
61
+ import time
59
62
 
60
63
  from typing import Optional, Union, Any
64
+
65
+ from http import HTTPStatus
61
66
  import requests
62
67
 
63
68
  logger = logging.getLogger("pyxecm.customizer.salesforce")
@@ -68,6 +73,9 @@ REQUEST_LOGIN_HEADERS = {
68
73
  }
69
74
 
70
75
  REQUEST_TIMEOUT = 60
76
+ REQUEST_RETRY_DELAY = 20
77
+ REQUEST_MAX_RETRIES = 3
78
+
71
79
  SALESFORCE_API_VERSION = "v60.0"
72
80
 
73
81
  class Salesforce(object):
@@ -205,6 +213,179 @@ class Salesforce(object):
205
213
 
206
214
  # end method definition
207
215
 
216
+ def do_request(
217
+ self,
218
+ url: str,
219
+ method: str = "GET",
220
+ headers: dict | None = None,
221
+ data: dict | None = None,
222
+ json_data: dict | None = None,
223
+ files: dict | None = None,
224
+ params: dict | None = None,
225
+ timeout: int | None = REQUEST_TIMEOUT,
226
+ show_error: bool = True,
227
+ show_warning: bool = False,
228
+ warning_message: str = "",
229
+ failure_message: str = "",
230
+ success_message: str = "",
231
+ max_retries: int = REQUEST_MAX_RETRIES,
232
+ retry_forever: bool = False,
233
+ parse_request_response: bool = True,
234
+ stream: bool = False,
235
+ verify: bool = True,
236
+ ) -> dict | None:
237
+ """Call an Salesforce REST API in a safe way
238
+
239
+ Args:
240
+ url (str): URL to send the request to.
241
+ method (str, optional): HTTP method (GET, POST, etc.). Defaults to "GET".
242
+ headers (dict | None, optional): Request Headers. Defaults to None.
243
+ data (dict | None, optional): Request payload. Defaults to None
244
+ files (dict | None, optional): Dictionary of {"name": file-tuple} for multipart encoding upload.
245
+ file-tuple can be a 2-tuple ("filename", fileobj) or a 3-tuple ("filename", fileobj, "content_type")
246
+ params (dict | None, optional): Add key-value pairs to the query string of the URL.
247
+ When you use the params parameter, requests automatically appends
248
+ the key-value pairs to the URL as part of the query string
249
+ timeout (int | None, optional): Timeout for the request in seconds. Defaults to REQUEST_TIMEOUT.
250
+ show_error (bool, optional): Whether or not an error should be logged in case of a failed REST call.
251
+ If False, then only a warning is logged. Defaults to True.
252
+ warning_message (str, optional): Specific warning message. Defaults to "". If not given the error_message will be used.
253
+ failure_message (str, optional): Specific error message. Defaults to "".
254
+ success_message (str, optional): Specific success message. Defaults to "".
255
+ max_retries (int, optional): How many retries on Connection errors? Default is REQUEST_MAX_RETRIES.
256
+ retry_forever (bool, optional): Eventually wait forever - without timeout. Defaults to False.
257
+ parse_request_response (bool, optional): should the response.text be interpreted as json and loaded into a dictionary. True is the default.
258
+ stream (bool, optional): parameter is used to control whether the response content should be immediately downloaded or streamed incrementally
259
+ verify (bool, optional): specify whether or not SSL certificates should be verified when making an HTTPS request. Default = True
260
+
261
+ Returns:
262
+ dict | None: Response of OTDS REST API or None in case of an error.
263
+ """
264
+
265
+ if headers is None:
266
+ logger.error("Missing request header. Cannot send request to Core Share!")
267
+ return None
268
+
269
+ # In case of an expired session we reauthenticate and
270
+ # try 1 more time. Session expiration should not happen
271
+ # twice in a row:
272
+ retries = 0
273
+
274
+ while True:
275
+ try:
276
+ response = requests.request(
277
+ method=method,
278
+ url=url,
279
+ data=data,
280
+ json=json_data,
281
+ files=files,
282
+ params=params,
283
+ headers=headers,
284
+ timeout=timeout,
285
+ stream=stream,
286
+ verify=verify,
287
+ )
288
+
289
+ if response.ok:
290
+ if success_message:
291
+ logger.info(success_message)
292
+ if parse_request_response:
293
+ return self.parse_request_response(response)
294
+ else:
295
+ return response
296
+ # Check if Session has expired - then re-authenticate and try once more
297
+ elif response.status_code == 401 and retries == 0:
298
+ logger.debug("Session has expired - try to re-authenticate...")
299
+ self.authenticate(revalidate=True)
300
+ # Make sure to not change an existing content type
301
+ # the do_request() method is called with:
302
+ headers = self.request_header(
303
+ content_type=headers.get("Content-Type", None)
304
+ )
305
+ retries += 1
306
+ else:
307
+ # Handle plain HTML responses to not pollute the logs
308
+ content_type = response.headers.get("content-type", None)
309
+ if content_type == "text/html":
310
+ response_text = "HTML content (only printed in debug log)"
311
+ else:
312
+ response_text = response.text
313
+
314
+ if show_error:
315
+ logger.error(
316
+ "%s; status -> %s/%s; error -> %s",
317
+ failure_message,
318
+ response.status_code,
319
+ HTTPStatus(response.status_code).phrase,
320
+ response_text,
321
+ )
322
+ elif show_warning:
323
+ logger.warning(
324
+ "%s; status -> %s/%s; warning -> %s",
325
+ warning_message if warning_message else failure_message,
326
+ response.status_code,
327
+ HTTPStatus(response.status_code).phrase,
328
+ response_text,
329
+ )
330
+ if content_type == "text/html":
331
+ logger.debug(
332
+ "%s; status -> %s/%s; warning -> %s",
333
+ failure_message,
334
+ response.status_code,
335
+ HTTPStatus(response.status_code).phrase,
336
+ response.text,
337
+ )
338
+ return None
339
+ except requests.exceptions.Timeout:
340
+ if retries <= max_retries:
341
+ logger.warning(
342
+ "Request timed out. Retrying in %s seconds...",
343
+ str(REQUEST_RETRY_DELAY),
344
+ )
345
+ retries += 1
346
+ time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
347
+ else:
348
+ logger.error(
349
+ "%s; timeout error",
350
+ failure_message,
351
+ )
352
+ if retry_forever:
353
+ # If it fails after REQUEST_MAX_RETRIES retries we let it wait forever
354
+ logger.warning("Turn timeouts off and wait forever...")
355
+ timeout = None
356
+ else:
357
+ return None
358
+ except requests.exceptions.ConnectionError:
359
+ if retries <= max_retries:
360
+ logger.warning(
361
+ "Connection error. Retrying in %s seconds...",
362
+ str(REQUEST_RETRY_DELAY),
363
+ )
364
+ retries += 1
365
+ time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
366
+ else:
367
+ logger.error(
368
+ "%s; connection error",
369
+ failure_message,
370
+ )
371
+ if retry_forever:
372
+ # If it fails after REQUEST_MAX_RETRIES retries we let it wait forever
373
+ logger.warning("Turn timeouts off and wait forever...")
374
+ timeout = None
375
+ time.sleep(REQUEST_RETRY_DELAY) # Add a delay before retrying
376
+ else:
377
+ return None
378
+ # end try
379
+ logger.debug(
380
+ "Retrying REST API %s call -> %s... (retry = %s)",
381
+ method,
382
+ url,
383
+ str(retries),
384
+ )
385
+ # end while True
386
+
387
+ # end method definition
388
+
208
389
  def parse_request_response(
209
390
  self,
210
391
  response_object: requests.Response,
@@ -409,32 +590,20 @@ class Salesforce(object):
409
590
 
410
591
  query = f"SELECT Id FROM {object_type} WHERE {name_field} = '{name}'"
411
592
 
412
- retries = 0
413
- while True:
414
- response = requests.get(
415
- url=request_url,
416
- headers=request_header,
417
- params={"q": query},
418
- timeout=REQUEST_TIMEOUT,
419
- )
420
- if response.ok:
421
- response = self.parse_request_response(response)
422
- object_id = self.get_result_value(response, "Id")
423
- return object_id
424
- elif response.status_code == 401 and retries == 0:
425
- logger.debug("Session has expired - try to re-authenticate...")
426
- self.authenticate(revalidate=True)
427
- request_header = self.request_header()
428
- retries += 1
429
- else:
430
- logger.error(
431
- "Failed to get Salesforce object ID for object type -> '%s' and object name -> '%s'; status -> %s; error -> %s",
432
- object_type,
433
- name,
434
- response.status_code,
435
- response.text,
436
- )
437
- return None
593
+ response = self.do_request(
594
+ method="GET",
595
+ url=request_url,
596
+ headers=request_header,
597
+ params={"q": query},
598
+ timeout=REQUEST_TIMEOUT,
599
+ failure_message="Failed to get Salesforce object ID for object type -> '{}' and object name -> '{}'".format(
600
+ object_type, name
601
+ ),
602
+ )
603
+ if not response:
604
+ return None
605
+
606
+ return self.get_result_value(response, "Id")
438
607
 
439
608
  # end method definition
440
609
 
@@ -509,28 +678,15 @@ class Salesforce(object):
509
678
  "Sending query -> %s to Salesforce; calling -> %s", query, request_url
510
679
  )
511
680
 
512
- retries = 0
513
- while True:
514
- response = requests.get(
515
- request_url, headers=request_header, timeout=REQUEST_TIMEOUT
516
- )
517
- if response.ok:
518
- return self.parse_request_response(response)
519
- elif response.status_code == 401 and retries == 0:
520
- logger.debug("Session has expired - try to re-authenticate...")
521
- self.authenticate(revalidate=True)
522
- request_header = self.request_header()
523
- retries += 1
524
- else:
525
- logger.error(
526
- "Failed to retrieve Salesforce object -> %s with %s = %s; status -> %s; error -> %s",
527
- object_type,
528
- search_field,
529
- search_value,
530
- response.status_code,
531
- response.text,
532
- )
533
- return None
681
+ return self.do_request(
682
+ method="GET",
683
+ url=request_url,
684
+ headers=request_header,
685
+ timeout=REQUEST_TIMEOUT,
686
+ failure_message="Failed to retrieve Salesforce object type -> '{}' with {} = {}".format(
687
+ object_type, search_field, search_value
688
+ ),
689
+ )
534
690
 
535
691
  # end method definition
536
692
 
@@ -654,26 +810,15 @@ class Salesforce(object):
654
810
  "Get Salesforce group with ID -> %s; calling -> %s", group_id, request_url
655
811
  )
656
812
 
657
- retries = 0
658
- while True:
659
- response = requests.get(
660
- request_url, headers=request_header, timeout=REQUEST_TIMEOUT
661
- )
662
- if response.ok:
663
- return self.parse_request_response(response)
664
- elif response.status_code == 401 and retries == 0:
665
- logger.debug("Session has expired - try to re-authenticate...")
666
- self.authenticate(revalidate=True)
667
- request_header = self.request_header()
668
- retries += 1
669
- else:
670
- logger.error(
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
813
+ return self.do_request(
814
+ method="GET",
815
+ url=request_url,
816
+ headers=request_header,
817
+ timeout=REQUEST_TIMEOUT,
818
+ failure_message="Failed to get Salesforce group with ID -> {}".format(
819
+ group_id
820
+ ),
821
+ )
677
822
 
678
823
  # end method definition
679
824
 
@@ -710,29 +855,14 @@ class Salesforce(object):
710
855
  "Adding Salesforce group -> %s; calling -> %s", group_name, request_url
711
856
  )
712
857
 
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
858
+ return self.do_request(
859
+ method="POST",
860
+ url=request_url,
861
+ headers=request_header,
862
+ data=json.dumps(payload),
863
+ timeout=REQUEST_TIMEOUT,
864
+ failure_message="Failed to add Salesforce group -> '{}'".format(group_name),
865
+ )
736
866
 
737
867
  # end method definition
738
868
 
@@ -740,7 +870,7 @@ class Salesforce(object):
740
870
  self,
741
871
  group_id: str,
742
872
  update_data: dict,
743
- ) -> dict:
873
+ ) -> dict | None:
744
874
  """Update a Salesforce group.
745
875
 
746
876
  Args:
@@ -764,29 +894,16 @@ class Salesforce(object):
764
894
  request_url,
765
895
  )
766
896
 
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
897
+ return self.do_request(
898
+ method="PATCH",
899
+ url=request_url,
900
+ headers=request_header,
901
+ json_data=update_data,
902
+ timeout=REQUEST_TIMEOUT,
903
+ failure_message="Failed to update Salesforce group with ID -> {}".format(
904
+ group_id
905
+ ),
906
+ )
790
907
 
791
908
  # end method definition
792
909
 
@@ -831,29 +948,16 @@ class Salesforce(object):
831
948
  request_url,
832
949
  )
833
950
 
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
951
+ return self.do_request(
952
+ method="GET",
953
+ url=request_url,
954
+ headers=request_header,
955
+ params=params,
956
+ timeout=REQUEST_TIMEOUT,
957
+ failure_message="Failed to get members of Salesforce group with ID -> {}".format(
958
+ group_id
959
+ ),
960
+ )
857
961
 
858
962
  # end method definition
859
963
 
@@ -891,29 +995,16 @@ class Salesforce(object):
891
995
  request_url,
892
996
  )
893
997
 
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,
913
- response.status_code,
914
- response.text,
915
- )
916
- return None
998
+ return self.do_request(
999
+ method="POST",
1000
+ url=request_url,
1001
+ headers=request_header,
1002
+ json_data=payload,
1003
+ timeout=REQUEST_TIMEOUT,
1004
+ failure_message="Failed to add member with ID -> {} to Salesforce group with ID -> {}".format(
1005
+ member_id, group_id
1006
+ ),
1007
+ )
917
1008
 
918
1009
  # end method definition
919
1010
 
@@ -935,8 +1026,7 @@ class Salesforce(object):
935
1026
  'url': '/services/data/v52.0/sobjects/Profile/00eDn000001msL8IAI'},
936
1027
  'Id': '00eDn000001msL8IAI',
937
1028
  'Name': 'Standard User',
938
- 'CreatedById':
939
- '005Dn000001rRodIAE',
1029
+ 'CreatedById': '005Dn000001rRodIAE',
940
1030
  'CreatedDate': '2022-11-30T15:30:54.000+0000',
941
1031
  'Description': None,
942
1032
  'LastModifiedById': '005Dn000001rUacIAE',
@@ -958,28 +1048,14 @@ class Salesforce(object):
958
1048
 
959
1049
  query = "SELECT Id, Name, CreatedById, CreatedDate, Description, LastModifiedById, LastModifiedDate, PermissionsCustomizeApplication, PermissionsEditTask, PermissionsImportLeads FROM Profile"
960
1050
 
961
- retries = 0
962
- while True:
963
- response = requests.get(
964
- request_url,
965
- headers=request_header,
966
- params={"q": query},
967
- timeout=REQUEST_TIMEOUT,
968
- )
969
- if response.ok:
970
- return self.parse_request_response(response)
971
- elif response.status_code == 401 and retries == 0:
972
- logger.debug("Session has expired - try to re-authenticate...")
973
- self.authenticate(revalidate=True)
974
- request_header = self.request_header()
975
- retries += 1
976
- else:
977
- logger.error(
978
- "Failed to get Salesforce user profiles; status -> %s; error -> %s",
979
- response.status_code,
980
- response.text,
981
- )
982
- return None
1051
+ return self.do_request(
1052
+ method="GET",
1053
+ url=request_url,
1054
+ headers=request_header,
1055
+ params={"q": query},
1056
+ timeout=REQUEST_TIMEOUT,
1057
+ failure_message="Failed to get Salesforce user profiles",
1058
+ )
983
1059
 
984
1060
  # end method definition
985
1061
 
@@ -1033,26 +1109,15 @@ class Salesforce(object):
1033
1109
  "Get Salesforce user with ID -> %s; calling -> %s", user_id, request_url
1034
1110
  )
1035
1111
 
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
1112
+ return self.do_request(
1113
+ method="GET",
1114
+ url=request_url,
1115
+ headers=request_header,
1116
+ timeout=REQUEST_TIMEOUT,
1117
+ failure_message="Failed to get Salesforce user with ID -> {}".format(
1118
+ user_id
1119
+ ),
1120
+ )
1056
1121
 
1057
1122
  # end method definition
1058
1123
 
@@ -1125,29 +1190,14 @@ class Salesforce(object):
1125
1190
  "Adding Salesforce user -> %s; calling -> %s", username, request_url
1126
1191
  )
1127
1192
 
1128
- retries = 0
1129
- while True:
1130
- response = requests.post(
1131
- request_url,
1132
- headers=request_header,
1133
- data=json.dumps(payload),
1134
- timeout=REQUEST_TIMEOUT,
1135
- )
1136
- if response.ok:
1137
- return self.parse_request_response(response)
1138
- elif response.status_code == 401 and retries == 0:
1139
- logger.debug("Session has expired - try to re-authenticate...")
1140
- self.authenticate(revalidate=True)
1141
- request_header = self.request_header()
1142
- retries += 1
1143
- else:
1144
- logger.error(
1145
- "Failed to add Salesforce user -> %s; status -> %s; error -> %s",
1146
- username,
1147
- response.status_code,
1148
- response.text,
1149
- )
1150
- return None
1193
+ return self.do_request(
1194
+ method="POST",
1195
+ url=request_url,
1196
+ headers=request_header,
1197
+ data=json.dumps(payload),
1198
+ timeout=REQUEST_TIMEOUT,
1199
+ failure_message="Failed to add Salesforce user -> {}".format(username),
1200
+ )
1151
1201
 
1152
1202
  # end method definition
1153
1203
 
@@ -1177,29 +1227,16 @@ class Salesforce(object):
1177
1227
  "Update Salesforce user with ID -> %s; calling -> %s", user_id, request_url
1178
1228
  )
1179
1229
 
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
1230
+ return self.do_request(
1231
+ method="PATCH",
1232
+ url=request_url,
1233
+ headers=request_header,
1234
+ json_data=update_data,
1235
+ timeout=REQUEST_TIMEOUT,
1236
+ failure_message="Failed to update Salesforce user with ID -> {}".format(
1237
+ user_id
1238
+ ),
1239
+ )
1203
1240
 
1204
1241
  # end method definition
1205
1242
 
@@ -1233,29 +1270,16 @@ class Salesforce(object):
1233
1270
 
1234
1271
  update_data = {"NewPassword": password}
1235
1272
 
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
1273
+ return self.do_request(
1274
+ method="POST",
1275
+ url=request_url,
1276
+ headers=request_header,
1277
+ json_data=update_data,
1278
+ timeout=REQUEST_TIMEOUT,
1279
+ failure_message="Failed to update password of Salesforce user with ID -> {}".format(
1280
+ user_id
1281
+ ),
1282
+ )
1259
1283
 
1260
1284
  # end method definition
1261
1285
 
@@ -1292,6 +1316,8 @@ class Salesforce(object):
1292
1316
  )
1293
1317
  return None
1294
1318
 
1319
+ # Content Type = None is important as upload calls need
1320
+ # a multipart header that is automatically selected if None is used:
1295
1321
  request_header = self.request_header(content_type=None)
1296
1322
 
1297
1323
  data = {"json": json.dumps({"cropX": 0, "cropY": 0, "cropSize": 200})}
@@ -1310,31 +1336,18 @@ class Salesforce(object):
1310
1336
  request_url,
1311
1337
  )
1312
1338
 
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
1339
+ return self.do_request(
1340
+ method="POST",
1341
+ url=request_url,
1342
+ headers=request_header,
1343
+ files=files,
1344
+ data=data,
1345
+ timeout=REQUEST_TIMEOUT,
1346
+ failure_message="Failed to update profile photo of Salesforce user with ID -> {}".format(
1347
+ user_id
1348
+ ),
1349
+ verify=False,
1350
+ )
1338
1351
 
1339
1352
  # end method definition
1340
1353
 
@@ -1383,32 +1396,22 @@ class Salesforce(object):
1383
1396
  payload.update(kwargs) # Add additional fields from kwargs
1384
1397
 
1385
1398
  logger.debug(
1386
- "Adding Salesforce account -> %s; calling -> %s", account_name, request_url
1399
+ "Adding Salesforce account -> '%s' (%s); calling -> %s",
1400
+ account_name,
1401
+ account_number,
1402
+ request_url,
1387
1403
  )
1388
1404
 
1389
- retries = 0
1390
- while True:
1391
- response = requests.post(
1392
- request_url,
1393
- headers=request_header,
1394
- data=json.dumps(payload),
1395
- timeout=REQUEST_TIMEOUT,
1396
- )
1397
- if response.ok:
1398
- return self.parse_request_response(response)
1399
- elif response.status_code == 401 and retries == 0:
1400
- logger.debug("Session has expired - try to re-authenticate...")
1401
- self.authenticate(revalidate=True)
1402
- request_header = self.request_header()
1403
- retries += 1
1404
- else:
1405
- logger.error(
1406
- "Failed to add Salesforce account -> %s; status -> %s; error -> %s",
1407
- account_name,
1408
- response.status_code,
1409
- response.text,
1410
- )
1411
- return None
1405
+ return self.do_request(
1406
+ method="POST",
1407
+ url=request_url,
1408
+ headers=request_header,
1409
+ data=json.dumps(payload),
1410
+ timeout=REQUEST_TIMEOUT,
1411
+ failure_message="Failed to add Salesforce account -> '{}' ({})".format(
1412
+ account_name, account_number
1413
+ ),
1414
+ )
1412
1415
 
1413
1416
  # end method definition
1414
1417
 
@@ -1447,32 +1450,22 @@ class Salesforce(object):
1447
1450
  payload.update(kwargs) # Add additional fields from kwargs
1448
1451
 
1449
1452
  logger.debug(
1450
- "Add Salesforce product -> %s; calling -> %s", product_name, request_url
1453
+ "Add Salesforce product -> '%s' (%s); calling -> %s",
1454
+ product_name,
1455
+ product_code,
1456
+ request_url,
1451
1457
  )
1452
1458
 
1453
- retries = 0
1454
- while True:
1455
- response = requests.post(
1456
- request_url,
1457
- headers=request_header,
1458
- data=json.dumps(payload),
1459
- timeout=REQUEST_TIMEOUT,
1460
- )
1461
- if response.ok:
1462
- return self.parse_request_response(response)
1463
- elif response.status_code == 401 and retries == 0:
1464
- logger.debug("Session has expired - try to re-authenticate...")
1465
- self.authenticate(revalidate=True)
1466
- request_header = self.request_header()
1467
- retries += 1
1468
- else:
1469
- logger.error(
1470
- "Failed to add Salesforce product -> %s; status -> %s; error -> %s",
1471
- product_name,
1472
- response.status_code,
1473
- response.text,
1474
- )
1475
- return None
1459
+ return self.do_request(
1460
+ method="POST",
1461
+ url=request_url,
1462
+ headers=request_header,
1463
+ data=json.dumps(payload),
1464
+ timeout=REQUEST_TIMEOUT,
1465
+ failure_message="Failed to add Salesforce product -> '{}' ({})".format(
1466
+ product_name, product_code
1467
+ ),
1468
+ )
1476
1469
 
1477
1470
  # end method definition
1478
1471
 
@@ -1520,32 +1513,17 @@ class Salesforce(object):
1520
1513
  payload.update(kwargs) # Add additional fields from kwargs
1521
1514
 
1522
1515
  logger.debug(
1523
- "Add Salesforce opportunity -> %s; calling -> %s", name, request_url
1516
+ "Add Salesforce opportunity -> '%s'; calling -> %s", name, request_url
1524
1517
  )
1525
1518
 
1526
- retries = 0
1527
- while True:
1528
- response = requests.post(
1529
- request_url,
1530
- headers=request_header,
1531
- data=json.dumps(payload),
1532
- timeout=REQUEST_TIMEOUT,
1533
- )
1534
- if response.ok:
1535
- return self.parse_request_response(response)
1536
- elif response.status_code == 401 and retries == 0:
1537
- logger.debug("Session has expired - try to re-authenticate...")
1538
- self.authenticate(revalidate=True)
1539
- request_header = self.request_header()
1540
- retries += 1
1541
- else:
1542
- logger.error(
1543
- "Failed to add Salesforce opportunity -> %s; status -> %s; error -> %s",
1544
- name,
1545
- response.status_code,
1546
- response.text,
1547
- )
1548
- return None
1519
+ return self.do_request(
1520
+ method="POST",
1521
+ url=request_url,
1522
+ headers=request_header,
1523
+ data=json.dumps(payload),
1524
+ timeout=REQUEST_TIMEOUT,
1525
+ failure_message="Failed to add Salesforce opportunity -> '{}'".format(name),
1526
+ )
1549
1527
 
1550
1528
  # end method definition
1551
1529
 
@@ -1603,31 +1581,16 @@ class Salesforce(object):
1603
1581
  payload["ProductId"] = product_id
1604
1582
  payload.update(kwargs) # Add additional fields from kwargs
1605
1583
 
1606
- logger.debug("Add Salesforce case -> %s; calling -> %s", subject, request_url)
1584
+ logger.debug("Add Salesforce case -> '%s'; calling -> %s", subject, request_url)
1607
1585
 
1608
- retries = 0
1609
- while True:
1610
- response = requests.post(
1611
- request_url,
1612
- headers=request_header,
1613
- data=json.dumps(payload),
1614
- timeout=REQUEST_TIMEOUT,
1615
- )
1616
- if response.ok:
1617
- return self.parse_request_response(response)
1618
- elif response.status_code == 401 and retries == 0:
1619
- logger.debug("Session has expired - try to re-authenticate...")
1620
- self.authenticate(revalidate=True)
1621
- request_header = self.request_header()
1622
- retries += 1
1623
- else:
1624
- logger.error(
1625
- "Failed to add Salesforce case -> %s; status -> %s; error -> %s",
1626
- subject,
1627
- response.status_code,
1628
- response.text,
1629
- )
1630
- return None
1586
+ return self.do_request(
1587
+ method="POST",
1588
+ url=request_url,
1589
+ headers=request_header,
1590
+ data=json.dumps(payload),
1591
+ timeout=REQUEST_TIMEOUT,
1592
+ failure_message="Failed to add Salesforce case -> '{}'".format(subject),
1593
+ )
1631
1594
 
1632
1595
  # end method definition
1633
1596
 
@@ -1677,32 +1640,17 @@ class Salesforce(object):
1677
1640
  payload.update(kwargs) # Add additional fields from kwargs
1678
1641
 
1679
1642
  logger.debug(
1680
- "Add Salesforce asset -> %s; calling -> %s", asset_name, request_url
1643
+ "Add Salesforce asset -> '%s'; calling -> %s", asset_name, request_url
1681
1644
  )
1682
1645
 
1683
- retries = 0
1684
- while True:
1685
- response = requests.post(
1686
- request_url,
1687
- headers=request_header,
1688
- data=json.dumps(payload),
1689
- timeout=REQUEST_TIMEOUT,
1690
- )
1691
- if response.ok:
1692
- return self.parse_request_response(response)
1693
- elif response.status_code == 401 and retries == 0:
1694
- logger.debug("Session has expired - try to re-authenticate...")
1695
- self.authenticate(revalidate=True)
1696
- request_header = self.request_header()
1697
- retries += 1
1698
- else:
1699
- logger.error(
1700
- "Failed to add Salesforce user -> %s; status -> %s; error -> %s",
1701
- asset_name,
1702
- response.status_code,
1703
- response.text,
1704
- )
1705
- return None
1646
+ return self.do_request(
1647
+ method="POST",
1648
+ url=request_url,
1649
+ headers=request_header,
1650
+ data=json.dumps(payload),
1651
+ timeout=REQUEST_TIMEOUT,
1652
+ failure_message="Failed to add Salesforce asset -> '{}'".format(asset_name),
1653
+ )
1706
1654
 
1707
1655
  # end method definition
1708
1656
 
@@ -1750,33 +1698,20 @@ class Salesforce(object):
1750
1698
  payload.update(kwargs) # Add additional fields from kwargs
1751
1699
 
1752
1700
  logger.debug(
1753
- "Adding Salesforce contract for account ID -> %s; calling -> %s",
1701
+ "Adding Salesforce contract for account with ID -> %s; calling -> %s",
1754
1702
  account_id,
1755
1703
  request_url,
1756
1704
  )
1757
1705
 
1758
- retries = 0
1759
- while True:
1760
- response = requests.post(
1761
- request_url,
1762
- headers=request_header,
1763
- data=json.dumps(payload),
1764
- timeout=REQUEST_TIMEOUT,
1765
- )
1766
- if response.ok:
1767
- return self.parse_request_response(response)
1768
- elif response.status_code == 401 and retries == 0:
1769
- logger.debug("Session has expired - try to re-authenticate...")
1770
- self.authenticate(revalidate=True)
1771
- request_header = self.request_header()
1772
- retries += 1
1773
- else:
1774
- logger.error(
1775
- "Failed to add Salesforce contract for account ID -> %s; status -> %s; error -> %s",
1776
- account_id,
1777
- response.status_code,
1778
- response.text,
1779
- )
1780
- return None
1706
+ return self.do_request(
1707
+ method="POST",
1708
+ url=request_url,
1709
+ headers=request_header,
1710
+ data=json.dumps(payload),
1711
+ timeout=REQUEST_TIMEOUT,
1712
+ failure_message="Failed to add Salesforce contract for account with ID -> {}".format(
1713
+ account_id
1714
+ ),
1715
+ )
1781
1716
 
1782
1717
  # end method definition