-
Notifications
You must be signed in to change notification settings - Fork 38
/
client.py
178 lines (165 loc) · 7.25 KB
/
client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import requests
from .objects.accounts import Accounts
from .objects.customfields import CustomFields
from .objects.customredirects import CustomRedirects
from .objects.dynamiccontent import DynamicContent
from .objects.emailclicks import EmailClicks
from .objects.emailtemplates import EmailTemplates
from .objects.forms import Forms
from .objects.lifecyclehistories import LifecycleHistories
from .objects.lifecyclestages import LifecycleStages
from .objects.lists import Lists
from .objects.listmemberships import ListMemberships
from .objects.emails import Emails
from .objects.prospects import Prospects
from .objects.opportunities import Opportunities
from .objects.prospectaccounts import ProspectAccounts
from .objects.tags import Tags
from .objects.tagobjects import TagObjects
from .objects.users import Users
from .objects.visits import Visits
from .objects.visitors import Visitors
from .objects.visitoractivities import VisitorActivities
from .objects.campaigns import Campaigns
from .errors import PardotAPIError
# Issue #1 (http://code.google.com/p/pybing/issues/detail?id=1)
# Python 2.6 has json built in, 2.5 needs simplejson
try:
import json
except ImportError:
import simplejson as json
BASE_URI = 'https://pi.pardot.com'
class PardotAPI(object):
def __init__(self, email, password, user_key, version=4):
self.email = email
self.password = password
self.user_key = user_key
self.api_key = None
self.version = version
self.accounts = Accounts(self)
self.campaigns = Campaigns(self)
self.customfields = CustomFields(self)
self.customredirects = CustomRedirects(self)
self.dynamiccontent = DynamicContent(self)
self.emailclicks = EmailClicks(self)
self.emails = Emails(self)
self.emailtemplates = EmailTemplates(self)
self.forms = Forms(self)
self.lifecyclehistories = LifecycleHistories(self)
self.lifecyclestages = LifecycleStages(self)
self.listmemberships = ListMemberships(self)
self.lists = Lists(self)
self.opportunities = Opportunities(self)
self.prospects = Prospects(self)
self.prospectaccounts = ProspectAccounts(self)
self.tags = Tags(self)
self.tagobjects = TagObjects(self)
self.users = Users(self)
self.visits = Visits(self)
self.visitors = Visitors(self)
self.visitoractivities = VisitorActivities(self)
def post(self, object_name, path=None, params=None, retries=0):
"""
Makes a POST request to the API. Checks for invalid requests that raise PardotAPIErrors. If the API key is
invalid, one re-authentication request is made, in case the key has simply expired. If no errors are raised,
returns either the JSON response, or if no JSON was returned, returns the HTTP response status code.
"""
if params is None:
params = {}
params.update({'user_key': self.user_key, 'api_key': self.api_key, 'format': 'json'})
try:
self._check_auth(object_name=object_name)
request = requests.post(self._full_path(object_name, self.version, path), data=params)
response = self._check_response(request)
return response
except PardotAPIError as err:
if err.message == 'Invalid API key or user key':
response = self._handle_expired_api_key(err, retries, 'post', object_name, path, params)
return response
else:
raise err
def get(self, object_name, path=None, params=None, retries=0):
"""
Makes a GET request to the API. Checks for invalid requests that raise PardotAPIErrors. If the API key is
invalid, one re-authentication request is made, in case the key has simply expired. If no errors are raised,
returns either the JSON response, or if no JSON was returned, returns the HTTP response status code.
"""
if params is None:
params = {}
params.update({'format': 'json'})
headers = self._build_auth_header()
try:
self._check_auth(object_name=object_name)
request = requests.get(self._full_path(object_name, self.version, path), params=params, headers=headers)
response = self._check_response(request)
return response
except PardotAPIError as err:
if err.message == 'Invalid API key or user key':
response = self._handle_expired_api_key(err, retries, 'get', object_name, path, params)
return response
else:
raise err
def _handle_expired_api_key(self, err, retries, method, object_name, path, params):
"""
Tries to refresh an expired API key and re-issue the HTTP request. If the refresh has already been attempted,
an error is raised.
"""
if retries != 0:
raise err
self.api_key = None
if self.authenticate():
response = getattr(self, method)(object_name=object_name, path=path, params=params, retries=1)
return response
else:
raise err
@staticmethod
def _full_path(object_name, version, path=None):
"""Builds the full path for the API request"""
full = '{0}/api/{1}/version/{2}'.format(BASE_URI, object_name, version)
if path:
return full + '{0}'.format(path)
return full
@staticmethod
def _check_response(response):
"""
Checks the HTTP response to see if it contains JSON. If it does, checks the JSON for error codes and messages.
Raises PardotAPIError if an error was found. If no error was found, returns the JSON. If JSON was not found,
returns the response status code.
"""
if response.headers.get('content-type') == 'application/json':
json = response.json()
error = json.get('err')
if error:
raise PardotAPIError(json_response=json)
return json
else:
return response.status_code
def _check_auth(self, object_name):
if object_name == 'login':
return
if self.api_key is None:
self.authenticate()
def authenticate(self):
"""
Authenticates the user and sets the API key if successful. Returns True if authentication is successful,
False if authentication fails.
"""
try:
auth = self.post('login', params={'email': self.email, 'password': self.password})
if type(auth) is int:
# sometimes the self.post method will return a status code instead of JSON response on failures
return False
self.api_key = auth.get('api_key', None)
if self.api_key is not None:
return True
return False
except PardotAPIError:
return False
def _build_auth_header(self):
"""
Builds Pardot Authorization Header to be used with GET requests
"""
if not self.user_key or not self.api_key:
raise Exception('Cannot build Authorization header. user or api key is empty')
auth_string = 'Pardot api_key=%s, user_key=%s' % (self.api_key, self.user_key)
return {'Authorization': auth_string}