salespyforce 1.4.0.dev0__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.
@@ -0,0 +1,53 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ :Module: salespyforce
4
+ :Synopsis: This is the ``__init__`` module for the salespyforce package
5
+ :Created By: Jeff Shurtliff
6
+ :Last Modified: Jeff Shurtliff
7
+ :Modified Date: 08 May 2023
8
+ """
9
+
10
+ from . import core
11
+ from .core import Salesforce
12
+ from .utils import version
13
+
14
+ __all__ = ['core', 'Salesforce']
15
+
16
+ # Define the package version by pulling from the highspot.utils.version module
17
+ __version__ = version.get_full_version()
18
+
19
+
20
+ # Allow the core.define_connection_info() function to be executed directly
21
+ def define_connection_info():
22
+ """This function prompts the user for the connection information.
23
+
24
+ :returns: The connection info in a dictionary
25
+ """
26
+ return core.define_connection_info()
27
+
28
+
29
+ # Allow the core.compile_connection_info() function to be executed directly
30
+ def compile_connection_info(base_url, org_id, username, password, endpoint_url,
31
+ client_id, client_secret, security_token):
32
+ """This function compiles the connection info into a dictionary that can be consumed by the core object.
33
+
34
+ :param base_url: The base URL of the Salesforce instance
35
+ :type base_url: str
36
+ :param org_id: The Org ID of the Salesforce instance
37
+ :type org_id: str
38
+ :param username: The username of the API user
39
+ :type username: str
40
+ :param password: The password of the API user
41
+ :type password: str
42
+ :param endpoint_url: The endpoint URL for the Salesforce instance
43
+ :type endpoint_url: str
44
+ :param client_id: The Client ID for the Salesforce instance
45
+ :type client_id: str
46
+ :param client_secret: The Client Secret for the Salesforce instance
47
+ :type client_secret: str
48
+ :param security_token: The Security Token for the Salesforce instance
49
+ :type security_token: str
50
+ :returns: The connection info in a dictionary
51
+ """
52
+ return core.compile_connection_info(base_url, org_id, username, password, endpoint_url,
53
+ client_id, client_secret, security_token)
salespyforce/api.py ADDED
@@ -0,0 +1,129 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ :Module: salespyforce.api
4
+ :Synopsis: Defines the basic functions associated with the Salesforce API
5
+ :Created By: Jeff Shurtliff
6
+ :Last Modified: Jeff Shurtliff
7
+ :Modified Date: 17 Feb 2023
8
+ """
9
+
10
+ import requests
11
+
12
+ from .utils import log_utils
13
+
14
+ # Initialize logging
15
+ logger = log_utils.initialize_logging(__name__)
16
+
17
+
18
+ def get(sfdc_object, endpoint, params=None, headers=None, timeout=30, show_full_error=True, return_json=True):
19
+ """This method performs a GET request against the Salesforce instance.
20
+ (`Reference <https://jereze.com/code/authentification-salesforce-rest-api-python/>`_)
21
+
22
+ :param sfdc_object: The instantiated SalesPyForce object
23
+ :param endpoint: The API endpoint to query
24
+ :type endpoint: str
25
+ :param params: The query parameters (where applicable)
26
+ :type params: dict, None
27
+ :param headers: Specific API headers to use when performing the API call
28
+ :type headers: dict, None
29
+ :param timeout: The timeout period in seconds (defaults to ``30``)
30
+ :type timeout: int, str, None
31
+ :param show_full_error: Determines if the full error message should be displayed (defaults to ``True``)
32
+ :type show_full_error: bool
33
+ :param return_json: Determines if the response should be returned in JSON format (defaults to ``True``)
34
+ :returns: The API response in JSON format or as a ``requests`` object
35
+ """
36
+ # Define the parameters as an empty dictionary if none are provided
37
+ params = {} if params is None else params
38
+
39
+ # Define the headers
40
+ default_headers = _get_headers(sfdc_object.access_token)
41
+ headers = default_headers if not headers else headers
42
+
43
+ # Make sure the endpoint begins with a slash
44
+ endpoint = f'/{endpoint}' if not endpoint.startswith('/') else endpoint
45
+
46
+ # Perform the API call
47
+ response = requests.get(f'{sfdc_object.instance_url}{endpoint}', headers=headers, params=params, timeout=timeout)
48
+ if response.status_code >= 300:
49
+ if show_full_error:
50
+ raise RuntimeError(f'The GET request failed with a {response.status_code} status code.\n'
51
+ f'{response.text}')
52
+ else:
53
+ raise RuntimeError(f'The GET request failed with a {response.status_code} status code.')
54
+ if return_json:
55
+ response = response.json()
56
+ return response
57
+
58
+
59
+ def api_call_with_payload(sfdc_object, method, endpoint, payload, params=None, headers=None, timeout=30,
60
+ show_full_error=True, return_json=True):
61
+ """This method performs a POST call against the Salesforce instance.
62
+ (`Reference <https://jereze.com/code/authentification-salesforce-rest-api-python/>`_)
63
+
64
+ :param sfdc_object: The instantiated SalesPyForce object
65
+ :param method: The API method (``post``, ``put``, or ``patch``)
66
+ :type method: str
67
+ :param endpoint: The API endpoint to query
68
+ :type endpoint: str
69
+ :param payload: The payload to leverage in the API call
70
+ :type payload: dict
71
+ :param params: The query parameters (where applicable)
72
+ :type params: dict, None
73
+ :param headers: Specific API headers to use when performing the API call
74
+ :type headers: dict, None
75
+ :param timeout: The timeout period in seconds (defaults to ``30``)
76
+ :type timeout: int, str, None
77
+ :param show_full_error: Determines if the full error message should be displayed (defaults to ``True``)
78
+ :type show_full_error: bool
79
+ :param return_json: Determines if the response should be returned in JSON format (defaults to ``True``)
80
+ :returns: The API response in JSON format or as a ``requests`` object
81
+ """
82
+ # Define the parameters as an empty dictionary if none are provided
83
+ params = {} if params is None else params
84
+
85
+ # Define the headers
86
+ default_headers = _get_headers(sfdc_object.access_token)
87
+ headers = default_headers if not headers else headers
88
+
89
+ # Make sure the endpoint begins with a slash
90
+ endpoint = f'/{endpoint}' if not endpoint.startswith('/') else endpoint
91
+
92
+ # Perform the API call
93
+ if method.lower() == 'post':
94
+ response = requests.post(f'{sfdc_object.instance_url}{endpoint}', json=payload, headers=headers, params=params,
95
+ timeout=timeout)
96
+ elif method.lower() == 'patch':
97
+ response = requests.patch(f'{sfdc_object.instance_url}{endpoint}', json=payload, headers=headers, params=params,
98
+ timeout=timeout)
99
+ elif method.lower() == 'put':
100
+ response = requests.put(f'{sfdc_object.instance_url}{endpoint}', json=payload, headers=headers, params=params,
101
+ timeout=timeout)
102
+ else:
103
+ raise ValueError('The API call method (POST or PATCH OR PUT) must be defined.')
104
+
105
+ # Examine the result
106
+ if response.status_code >= 300:
107
+ if show_full_error:
108
+ raise RuntimeError(f'The POST request failed with a {response.status_code} status code.\n'
109
+ f'{response.text}')
110
+ else:
111
+ raise RuntimeError(f'The POST request failed with a {response.status_code} status code.')
112
+ if return_json:
113
+ try:
114
+ response = response.json()
115
+ except Exception as exc:
116
+ print(f'Failed to convert the API response to JSON format due to the following exception: {exc}')
117
+ return response
118
+
119
+
120
+ def _get_headers(_access_token, _header_type='default'):
121
+ """This function returns the appropriate HTTP headers to use for different types of API calls."""
122
+ headers = {
123
+ 'content-type': 'application/json',
124
+ 'accept-encoding': 'gzip',
125
+ 'authorization': f'Bearer {_access_token}'
126
+ }
127
+ if _header_type == 'articles':
128
+ headers['accept-language'] = 'en-US'
129
+ return headers
@@ -0,0 +1,167 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ :Module: salespyforce.chatter
4
+ :Synopsis: Defines the Chatter-related functions associated with the Salesforce Connect API
5
+ :Created By: Jeff Shurtliff
6
+ :Last Modified: Jeff Shurtliff
7
+ :Modified Date: 13 Mar 2023
8
+ """
9
+
10
+ from .utils import log_utils
11
+
12
+ # Initialize logging
13
+ logger = log_utils.initialize_logging(__name__)
14
+
15
+
16
+ def _get_site_endpoint_segment(_site_id=None):
17
+ """This function constructs the endpoint segment when querying a specific Experience Cloud site.
18
+
19
+ :param _site_id: The Site ID of the Experience Cloud site
20
+ :type _site_id: str
21
+ :returns: The API endpoint segment (or a blank string if no Site ID was provided)
22
+ """
23
+ _endpoint_segment = f'/connect/communities/{_site_id}' if _site_id else ''
24
+ return _endpoint_segment
25
+
26
+
27
+ def get_my_news_feed(sfdc_object, site_id=None):
28
+ """This function retrieves the news feed for the user calling the function.
29
+ (`Reference <https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickreference_get_news_feed.htm>`_)
30
+
31
+ :param sfdc_object: The instantiated SalesPyForce object
32
+ :type sfdc_object: class[salespyforce.Salesforce]
33
+ :param site_id: The ID of an Experience Cloud site against which to query (optional)
34
+ :type site_id: str, None
35
+ :returns: The news feed data
36
+ :raises: :py:exc:`RuntimeError`
37
+ """
38
+ site_segment = _get_site_endpoint_segment(site_id)
39
+ endpoint = f'/services/data/{sfdc_object.version}{site_segment}/chatter/feeds/news/me/feed-elements'
40
+ return sfdc_object.get(endpoint)
41
+
42
+
43
+ def get_user_news_feed(sfdc_object, user_id, site_id=None):
44
+ """This function retrieves another user's news feed.
45
+ (`Reference <https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickreference_get_user_profile_feed.htm>`_)
46
+
47
+ :param sfdc_object: The instantiated SalesPyForce object
48
+ :type sfdc_object: class[salespyforce.Salesforce]
49
+ :param user_id: The ID of the user whose feed you wish to return
50
+ :type user_id: str
51
+ :param site_id: The ID of an Experience Cloud site against which to query (optional)
52
+ :type site_id: str, None
53
+ :returns: The news feed data
54
+ :raises: :py:exc:`RuntimeError`
55
+ """
56
+ site_segment = _get_site_endpoint_segment(site_id)
57
+ endpoint = f'/services/data/{sfdc_object.version}{site_segment}/chatter/feeds/user-profile/{user_id}/feed-elements'
58
+ return sfdc_object.get(endpoint)
59
+
60
+
61
+ def get_group_feed(sfdc_object, group_id, site_id=None):
62
+ """This function retrieves a group's news feed.
63
+ (`Reference <https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickreference_get_group_feed.htm>`_)
64
+
65
+ :param sfdc_object: The instantiated SalesPyForce object
66
+ :type sfdc_object: class[salespyforce.Salesforce]
67
+ :param group_id: The ID of the group whose feed you wish to return
68
+ :type group_id: str
69
+ :param site_id: The ID of an Experience Cloud site against which to query (optional)
70
+ :type site_id: str, None
71
+ :returns: The news feed data
72
+ :raises: :py:exc:`RuntimeError`
73
+ """
74
+ site_segment = _get_site_endpoint_segment(site_id)
75
+ endpoint = f'/services/data/{sfdc_object.version}{site_segment}/chatter/feeds/record/{group_id}/feed-elements'
76
+ return sfdc_object.get(endpoint)
77
+
78
+
79
+ def post_feed_item(sfdc_object, subject_id, message_text=None, message_segments=None, site_id=None, created_by_id=None):
80
+ """This function publishes a new Chatter feed item.
81
+ (`Reference <https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickreference_post_feed_item.htm>`_)
82
+
83
+ :param sfdc_object: The instantiated SalesPyForce object
84
+ :type sfdc_object: class[salespyforce.Salesforce]
85
+ :param subject_id: The Subject ID against which to publish the feed item (e.g. ``0F9B000000000W2``)
86
+ :type subject_id: str
87
+ :param message_text: Plaintext to be used as the message body
88
+ :type message_segments: str, None
89
+ :param message_segments: Collection of message segments to use instead of a plaintext message
90
+ :type message_segments: list, None
91
+ :param site_id: The ID of an Experience Cloud site against which to query (optional)
92
+ :type site_id: str, None
93
+ :param created_by_id: The ID of the user to impersonate (**Experimental**)
94
+ :type created_by_id: str, None
95
+ :returns: The response of the POST request
96
+ :raises: :py:exc:`RuntimeError`
97
+ """
98
+ site_segment = _get_site_endpoint_segment(site_id)
99
+ if not any((message_text, message_segments)):
100
+ raise RuntimeError('Message text or message segments are required to post a feed item.')
101
+ if not message_segments:
102
+ message_segments = _construct_simple_message_segment(message_text)
103
+ body = {
104
+ 'body': {
105
+ 'messageSegments': message_segments
106
+ },
107
+ 'feedElementType': 'FeedItem',
108
+ 'subjectId': subject_id,
109
+ }
110
+ if created_by_id:
111
+ body['createdById'] = created_by_id
112
+ endpoint = f'/services/data/{sfdc_object.version}{site_segment}/chatter/feed-elements?' \
113
+ f'feedElementType=FeedItem&subjectId={subject_id}'
114
+ return sfdc_object.post(endpoint=endpoint, payload=body)
115
+
116
+
117
+ def post_comment(sfdc_object, feed_element_id, message_text=None, message_segments=None, site_id=None, created_by_id=None):
118
+ """This function publishes a comment on a Chatter feed item.
119
+ (`Reference <https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickreference_post_comment_to_feed_element.htm>`_)
120
+
121
+ :param sfdc_object: The instantiated SalesPyForce object
122
+ :type sfdc_object: class[salespyforce.Salesforce]
123
+ :param feed_element_id: The ID of the feed element on which to post the comment
124
+ :type feed_element_id: str
125
+ :param message_text: Plaintext to be used as the message body
126
+ :type message_segments: str, None
127
+ :param message_segments: Collection of message segments to use instead of a plaintext message
128
+ :type message_segments: list, None
129
+ :param site_id: The ID of an Experience Cloud site against which to query (optional)
130
+ :type site_id: str, None
131
+ :param created_by_id: The ID of the user to impersonate (**Experimental**)
132
+ :type created_by_id: str, None
133
+ :returns: The response of the POST request
134
+ :raises: :py:exc:`RuntimeError`
135
+ """
136
+ site_segment = _get_site_endpoint_segment(site_id)
137
+ if not any((message_text, message_segments)):
138
+ raise RuntimeError('Message text or message segments are required to post a feed comment.')
139
+ if not message_segments:
140
+ message_segments = _construct_simple_message_segment(message_text)
141
+ body = {
142
+ 'body': {
143
+ 'messageSegments': message_segments
144
+ }
145
+ }
146
+ if created_by_id:
147
+ body['createdById'] = created_by_id
148
+ endpoint = f'/services/data/{sfdc_object.version}{site_segment}/chatter/feed-elements/' \
149
+ f'{feed_element_id}/capabilities/comments/items'
150
+ return sfdc_object.post(endpoint=endpoint, payload=body)
151
+
152
+
153
+ def _construct_simple_message_segment(_message_text):
154
+ """This function constructs a simple message segments collection to be used in an API payload.
155
+
156
+ :param _message_text: The plaintext message to be embedded in a message segment.
157
+ :type _message_text: str
158
+ :returns: The constructed message segments payload
159
+ """
160
+ _message_segments = [
161
+ {
162
+ 'type': 'text',
163
+ 'text': _message_text
164
+ }
165
+ ]
166
+ return _message_segments
167
+