diff --git a/pypardot/client.py b/pypardot/client.py index 0c4cc47..d8c8b12 100644 --- a/pypardot/client.py +++ b/pypardot/client.py @@ -1,26 +1,4 @@ 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 @@ -41,28 +19,14 @@ def __init__(self, email, password, user_key, version=4): 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) + self._load_objects() + + def _load_objects(self): + if self.version == 3: + from .objects_v3 import load_objects + else: + from .objects import load_objects + load_objects(self) def post(self, object_name, path=None, params=None, retries=0): """ @@ -175,4 +139,4 @@ def _build_auth_header(self): 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} \ No newline at end of file + return {'Authorization': auth_string} diff --git a/pypardot/objects/__init__.py b/pypardot/objects/__init__.py index 8b13789..fb6f65a 100644 --- a/pypardot/objects/__init__.py +++ b/pypardot/objects/__init__.py @@ -1 +1,47 @@ +from .accounts import Accounts +from .customfields import CustomFields +from .customredirects import CustomRedirects +from .dynamiccontent import DynamicContent +from .emailclicks import EmailClicks +from .emailtemplates import EmailTemplates +from .forms import Forms +from .lifecyclehistories import LifecycleHistories +from .lifecyclestages import LifecycleStages +from .lists import Lists +from .listmemberships import ListMemberships +from .emails import Emails +from .prospects import Prospects +from .opportunities import Opportunities +from .prospectaccounts import ProspectAccounts +from .tags import Tags +from .tagobjects import TagObjects +from .users import Users +from .visits import Visits +from .visitors import Visitors +from .visitoractivities import VisitorActivities +from .campaigns import Campaigns + +def load_objects(client): + client.accounts = Accounts(client) + client.campaigns = Campaigns(client) + client.customfields = CustomFields(client) + client.customredirects = CustomRedirects(client) + client.dynamiccontent = DynamicContent(client) + client.emailclicks = EmailClicks(client) + client.emails = Emails(client) + client.emailtemplates = EmailTemplates(client) + client.forms = Forms(client) + client.lifecyclehistories = LifecycleHistories(client) + client.lifecyclestages = LifecycleStages(client) + client.listmemberships = ListMemberships(client) + client.lists = Lists(client) + client.opportunities = Opportunities(client) + client.prospects = Prospects(client) + client.prospectaccounts = ProspectAccounts(client) + client.tags = Tags(client) + client.tagobjects = TagObjects(client) + client.users = Users(client) + client.visits = Visits(client) + client.visitors = Visitors(client) + client.visitoractivities = VisitorActivities(client) diff --git a/pypardot/objects_v3/__init__.py b/pypardot/objects_v3/__init__.py new file mode 100644 index 0000000..b2765f7 --- /dev/null +++ b/pypardot/objects_v3/__init__.py @@ -0,0 +1,27 @@ +# This module (objects) was originally imported from Josh Geller's original implementation +# https://github.com/joshgeller/PyPardot/tree/349dde1fad561f32a425324005c4f2a0c4a23d9b/pypardot/objects +# The code in __init__.py was added to be integrated with PyPardot4 to support +# difference in the implementations between the versions 3 and 4. +from .lists import Lists +from .emails import Emails +from .prospects import Prospects +from .opportunities import Opportunities +from .accounts import Accounts +from .users import Users +from .visits import Visits +from .visitors import Visitors +from .visitoractivities import VisitorActivities +from .campaigns import Campaigns + + +def load_objects(client): + client.lists = Lists(client) + client.emails = Emails(client) + client.prospects = Prospects(client) + client.opportunities = Opportunities(client) + client.accounts = Accounts(client) + client.users = Users(client) + client.visits = Visits(client) + client.visitors = Visitors(client) + client.visitoractivities = VisitorActivities(client) + client.campaigns = Campaigns(client) diff --git a/pypardot/objects_v3/accounts.py b/pypardot/objects_v3/accounts.py new file mode 100644 index 0000000..d1ebece --- /dev/null +++ b/pypardot/objects_v3/accounts.py @@ -0,0 +1,67 @@ +class Accounts(object): + """ + A class to query and use Pardot accounts. + Account field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#prospectAccount + """ + + def __init__(self, client): + self.client = client + + def query(self, **kwargs): + """ + Returns the prospect accounts matching the specified criteria parameters. + Supported search criteria: http://developer.pardot.com/kb/api-version-3/prospect-accounts/#supported-search-criteria + """ + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['prospectAccount'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['prospectAccount'] = [] + elif result['total_results'] == 1: + result['prospectAccount'] = [result['prospectAccount']] + + return result + + def create(self, **kwargs): + """Creates a new prospect account.""" + response = self._post(path='/do/create', params=kwargs) + return response + + def describe(self, **kwargs): + """ + Returns the field metadata for prospect accounts, explaining what fields are available, their types, whether + they are required, and their options (for dropdowns, radio buttons, etc). + """ + response = self._get(path='/do/describe', params=kwargs) + return response + + def read(self, id=None, **kwargs): + """ + Returns the data for the prospect account specified by . is the Pardot ID of the target prospect + account. + """ + response = self._post(path='/do/read/id/{id}'.format(id=id), params=kwargs) + return response + + def update(self, id=None, **kwargs): + """ + Updates the data for the prospect account specified by . is the Pardot ID of the target prospect + account. + """ + response = self._post(path='/do/update/id/{id}'.format(id=id), params=kwargs) + return response + + def _get(self, object_name='prospectAccount', path=None, params=None): + """GET requests for the Account object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='prospectAccount', path=None, params=None): + """POST requests for the Account object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/campaigns.py b/pypardot/objects_v3/campaigns.py new file mode 100644 index 0000000..c6dc1e0 --- /dev/null +++ b/pypardot/objects_v3/campaigns.py @@ -0,0 +1,44 @@ +class Campaigns(object): + """ + A class to query and use Pardot campaigns. + Campaign field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#campaign + """ + + def __init__(self, client): + self.client = client + + def query(self, **kwargs): + """ + Returns the campaigns matching the specified criteria parameters. + Supported search criteria: http://developer.pardot.com/kb/api-version-3/campaigns/#supported-search-criteria + """ + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['campaign'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['campaign'] = [] + elif result['total_results'] == 1: + result['campaign'] = [result['campaign']] + + return result + + def read_by_id(self, id=None, **kwargs): + """ + Returns the data for the campaign specified by . is the Pardot ID of the target campaign.""" + response = self._post(path='/do/read/id/{id}'.format(id=id), params=kwargs) + return response + + def _get(self, object_name='campaign', path=None, params=None): + """GET requests for the Campaign object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='campaign', path=None, params=None): + """POST requests for the Campaign object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/emails.py b/pypardot/objects_v3/emails.py new file mode 100644 index 0000000..f938c36 --- /dev/null +++ b/pypardot/objects_v3/emails.py @@ -0,0 +1,56 @@ +class Emails(object): + """ + A class to query and send Pardot emails. + Email field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#email + """ + + def __init__(self, client): + self.client = client + + def send_to_email(self, prospect_email=None, **kwargs): + """ + Sends an email to the prospect identified by . + Required parameters: (email_template_id OR (text_content, name, subject, & ((from_email & from_name) OR from_user_id))) + """ + response = self._post( + path='/do/send/prospect_email/{prospect_email}'.format(prospect_email=prospect_email), + params=kwargs) + return response + + def send_to_id(self, prospect_id=None, **kwargs): + """ + Sends an email to the prospect identified by . + Required parameters: (email_template_id OR (text_content, name, subject, & ((from_email & from_name) OR from_user_id))) + """ + response = self._post( + path='/do/send/prospect_id/{prospect_id}'.format(prospect_id=prospect_id), params=kwargs) + return response + + def send_to_lists(self, **kwargs): + """ + Sends an email to the lists identified by . + Required parameters: (email_template_id OR (text_content, name, subject, & ((from_email & from_name) OR from_user_id))) + """ + kwargs['list_ids'] = kwargs.get('list_ids', None) + response = self._post( + path='/do/send/', params=kwargs) + return response + + def read(self, id=None): + """Returns the data for the email specified by . is the Pardot ID of the target email.""" + response = self._post(path='/do/read/id/{id}'.format(id=id)) + return response + + def _get(self, object_name='email', path=None, params=None): + """GET requests for the Email object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='email', path=None, params=None): + """POST requests for the Email object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/lists.py b/pypardot/objects_v3/lists.py new file mode 100644 index 0000000..43304e4 --- /dev/null +++ b/pypardot/objects_v3/lists.py @@ -0,0 +1,45 @@ +class Lists(object): + """ + A class to query and use Pardot lists. + List field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#list + """ + + def __init__(self, client): + self.client = client + + def query(self, **kwargs): + """ + Returns the lists matching the specified criteria parameters. + Supported search criteria: http://developer.pardot.com/kb/api-version-3/lists/#supported-search-criteria + """ + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['list'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['list'] = [] + elif result['total_results'] == 1: + result['list'] = [result['list']] + + return result + + def read(self, id=None): + """ + Returns the data for the list specified by . is the Pardot ID of the target list. + """ + response = self._post(path='/do/read/id/{id}'.format(id=id)) + return response + + def _get(self, object_name='list', path=None, params=None): + """GET requests for the List object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='list', path=None, params=None): + """POST requests for the List object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/opportunities.py b/pypardot/objects_v3/opportunities.py new file mode 100644 index 0000000..93a9760 --- /dev/null +++ b/pypardot/objects_v3/opportunities.py @@ -0,0 +1,91 @@ +class Opportunities(object): + """ + A class to query and use Pardot opportunities. + Opportunity field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#opportunity + """ + + def __init__(self, client): + self.client = client + + def query(self, **kwargs): + """ + Returns the opportunities matching the specified criteria parameters. + Supported search criteria: http://developer.pardot.com/kb/api-version-3/opportunities/#supported-search-criteria + """ + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['opportunity'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['opportunity'] = [] + elif result['total_results'] == 1: + result['opportunity'] = [result['opportunity']] + + return result + + def create_by_email(self, prospect_email=None, name=None, value=None, probability=None, **kwargs): + """ + Creates a new opportunity using the specified data. must correspond to an existing prospect. + """ + kwargs.update({'name': name, 'value': value, 'probability': probability}) + response = self._post( + path='/do/create/prospect_email/{prospect_email}'.format(prospect_email=prospect_email), + params=kwargs) + return response + + def create_by_id(self, prospect_id=None, name=None, value=None, probability=None, **kwargs): + """ + Creates a new opportunity using the specified data. must correspond to an existing prospect. + """ + kwargs.update({'name': name, 'value': value, 'probability': probability}) + response = self._post( + path='/do/create/prospect_id/{prospect_id}'.format(prospect_id=prospect_id), + params=kwargs) + return response + + def read(self, id=None): + """ + Returns the data for the opportunity specified by , including campaign assignment and associated visitor + activities. is the Pardot ID for the target opportunity. + """ + response = self._post(path='/do/read/id/{id}'.format(id=id)) + return response + + def update(self, id=None): + """ + Updates the provided data for the opportunity specified by . is the Pardot ID for the target + opportunity. Fields that are not updated by the request remain unchanged. Returns an updated version of the + opportunity. + """ + response = self._post(path='/do/update/id/{id}'.format(id=id)) + return response + + def delete(self, id=None): + """ + Deletes the opportunity specified by . is the Pardot ID for the target opportunity. Returns no response + on success. + """ + response = self._post(path='/do/delete/id/{id}'.format(id=id)) + return response + + def undelete(self, id=None): + """ + Un-deletes the opportunity specified by . is the Pardot ID for the target opportunity. Returns no + response on success. + """ + response = self._post(path='/do/undelete/id/{id}'.format(id=id)) + return response + + def _get(self, object_name='opportunity', path=None, params=None): + """GET requests for the Opportunity object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='opportunity', path=None, params=None): + """POST requests for the Opportunity object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/prospects.py b/pypardot/objects_v3/prospects.py new file mode 100644 index 0000000..7e38e48 --- /dev/null +++ b/pypardot/objects_v3/prospects.py @@ -0,0 +1,187 @@ +from ..errors import PardotAPIArgumentError + + +class Prospects(object): + """ + A class to query and use Pardot prospects. + Prospect field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#prospect + """ + + def __init__(self, client): + self.client = client + + def query(self, **kwargs): + """ + Returns the prospects matching the specified criteria parameters. + Supported search criteria: http://developer.pardot.com/kb/api-version-3/prospects/#supported-search-criteria + """ + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['prospect'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['prospect'] = [] + elif result['total_results'] == 1: + result['prospect'] = [result['prospect']] + + return result + + def assign_by_email(self, email=None, **kwargs): + """ + Assigns or reassigns the prospect specified by to a specified Pardot user or group. One (and only one) + of the following parameters must be provided to identify the target user or group: , , or + . Returns an updated version of the prospect. + """ + response = self._post(path='/do/assign/email/{email}'.format(email=email), params=kwargs) + return response + + def assign_by_id(self, id=None, **kwargs): + """ + Assigns or reassigns the prospect specified by to a specified Pardot user or group. One (and only one) of + the following parameters must be provided to identify the target user or group: , , or + . Returns an updated version of the prospect. + """ + response = self._post(path='/do/assign/id/{id}'.format(id=id), params=kwargs) + return response + + def unassign_by_email(self, email=None, **kwargs): + """Unassigns the prospect specified by . Returns an updated version of the prospect.""" + response = self._post(path='/do/unassign/email/{email}'.format(email=email), params=kwargs) + return response + + def unassign_by_id(self, id=None, **kwargs): + """Unassigns the prospect specified by . Returns an updated version of the prospect.""" + response = self._post(path='/do/unassign/id/{id}'.format(id=id), params=kwargs) + return response + + def create_by_email(self, email=None, **kwargs): + """ + Creates a new prospect using the specified data. must be a unique email address. Returns the new prospect. + """ + if not email: + raise PardotAPIArgumentError('email is required to create a prospect.') + response = self._post(path='/do/create/email/{email}'.format(email=email), params=kwargs) + return response + + def read_by_email(self, email=None, **kwargs): + """ + Returns data for the prospect specified by , including campaign assignment, profile criteria + matching statuses, associated visitor activities, email list subscriptions, and custom field data. + is the email address of the target prospect. + """ + if not email: + raise PardotAPIArgumentError('email is required to read a prospect.') + response = self._post(path='/do/read/email/{email}'.format(email=email), params=kwargs) + return response + + def read_by_id(self, id=None, **kwargs): + """ + Returns data for the prospect specified by , including campaign assignment, profile criteria + matching statuses, associated visitor activities, email list subscriptions, and custom field data. + is the Pardot ID of the target prospect. + """ + if not id: + raise PardotAPIArgumentError('id is required to read a prospect.') + response = self._post(path='/do/read/id/{id}'.format(id=id), params=kwargs) + return response + + def update_by_email(self, email=None, **kwargs): + """ + Updates the provided data for a prospect specified by . is the email address of the + prospect. Fields that are not updated by the request remain unchanged. + """ + if not email: + raise PardotAPIArgumentError('email is required to update a prospect.') + response = self._post(path='/do/update/email/{email}'.format(email=email), params=kwargs) + return response + + def update_by_id(self, id=None, **kwargs): + """ + Updates the provided data for a prospect specified by . is the Pardot ID of the prospect. + Fields that are not updated by the request remain unchanged. + """ + if not id: + raise PardotAPIArgumentError('id is required to update a prospect.') + response = self._post(path='/do/update/id/{id}'.format(id=id), params=kwargs) + return response + + def upsert_by_email(self, email=None, **kwargs): + """ + Updates the provided data for the prospect specified by . If a prospect with the provided email address + does not yet exist, a new prospect is created using the value. Fields that are not updated by the + request remain unchanged. + """ + if not email: + raise PardotAPIArgumentError('email is required to upsert a prospect.') + response = self._post(path='/do/upsert/email/{email}'.format(email=email), params=kwargs) + return response + + def upsert_by_id(self, id=None, **kwargs): + """ + Updates the provided data for the prospect specified by . If an value is provided, it is used to + update the prospect's email address. If a prospect with the provided ID is not found, Pardot searches for a + prospect identified by . If a prospect with the provided email address does not yet exist, a new + prospect is created using value. Fields that are not updated by the request remain unchanged. + """ + if not id: + raise PardotAPIArgumentError('id is required to upsert a prospect.') + response = self._post(path='/do/upsert/id/{id}'.format(id=id), params=kwargs) + return response + + def delete_by_email(self, email=None, **kwargs): + """Deletes the prospect specified by . Returns True if operation was successful.""" + if not email: + raise PardotAPIArgumentError('email is required to delete a prospect.') + response = self._post(path='/do/delete/email/{email}'.format(email=email), params=kwargs) + if response == 204: + return True + return False + + def delete_by_id(self, id=None, **kwargs): + """Deletes the prospect specified by . Returns True if operation was successful.""" + if not id: + raise PardotAPIArgumentError('id is required to delete a prospect.') + response = self._post(path='/do/delete/id/{id}'.format(id=id), params=kwargs) + if response == 204: + return True + return False + + def update_field_by_id(self, id=None, field_name=None, field_value=None): + """Updates the provided field for the prospect specified by . Returns the updated prospect.""" + response = self.update_by_id(id=id, **{field_name: field_value}) + return response + + def update_field_by_email(self, email=None, field_name=None, field_value=None): + """Updates the provided field for the prospect specified by . Returns the updated prospect.""" + response = self.update_by_email(email=email, **{field_name: field_value}) + return response + + def read_field_by_email(self, email=None, field_name=None): + """Returns the value of the provided field for the prospect specified by .""" + response = self.read_by_email(email=email) + return response.get('prospect').get(field_name) + + def read_field_by_id(self, id=None, field_name=None): + """Returns the value of the provided field for the prospect specified by .""" + response = self.read_by_id(id=id) + return response.get('prospect').get(field_name) + + def add_to_list(self, prospect_id=None, list_id=None): + """Adds the prospect specified by to the list specified by .""" + params = {'prospect_id': prospect_id, 'list_id': list_id} + response = self._post(object_name='listMembership', path='/do/create', params=params) + return response + + def _get(self, object_name='prospect', path=None, params=None): + """GET requests for the Prospect object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='prospect', path=None, params=None): + """POST requests for the Prospect object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/tests/.gitignore b/pypardot/objects_v3/tests/.gitignore new file mode 100644 index 0000000..4acd06b --- /dev/null +++ b/pypardot/objects_v3/tests/.gitignore @@ -0,0 +1 @@ +config.py diff --git a/pypardot/objects_v3/tests/README.md b/pypardot/objects_v3/tests/README.md new file mode 100644 index 0000000..564b158 --- /dev/null +++ b/pypardot/objects_v3/tests/README.md @@ -0,0 +1,5 @@ +# Integration Testing + +Copy config.py.example to config.py and fill in the details. + +Running the tests will create and delete objects in the account, so make sure to use a testing account. Pardot will set up a training account for testing purposes if asked. diff --git a/pypardot/objects_v3/tests/__init__.py b/pypardot/objects_v3/tests/__init__.py new file mode 100644 index 0000000..ca11dbc --- /dev/null +++ b/pypardot/objects_v3/tests/__init__.py @@ -0,0 +1,4 @@ +# This module (objects) was originally imported from Josh Geller's original implementation +# https://github.com/joshgeller/PyPardot/tree/349dde1fad561f32a425324005c4f2a0c4a23d9b/pypardot/objects + + diff --git a/pypardot/objects_v3/tests/config.py.example b/pypardot/objects_v3/tests/config.py.example new file mode 100644 index 0000000..a5f6385 --- /dev/null +++ b/pypardot/objects_v3/tests/config.py.example @@ -0,0 +1,3 @@ +PARDOT_USER = 'pardot_account_email@example.com' +PARDOT_PASSWORD = 'The Sooper Secret Password 99' +PARDOT_USER_KEY = 'Pardot user key for the user' diff --git a/pypardot/objects_v3/tests/test_prospects.py b/pypardot/objects_v3/tests/test_prospects.py new file mode 100644 index 0000000..31c9e2e --- /dev/null +++ b/pypardot/objects_v3/tests/test_prospects.py @@ -0,0 +1,118 @@ +import unittest + +from pypardot.client import PardotAPI +from pypardot.errors import PardotAPIArgumentError, PardotAPIError + +try: + from pypardot.objects.tests.config import * + CONFIG_EXISTS = True +except SystemError as e: + CONFIG_EXISTS = False + + +@unittest.skipUnless(CONFIG_EXISTS, 'Requires Pardot configuration in config.py') +class TestProspects(unittest.TestCase): + def setUp(self): + self.pardot = PardotAPI(email=PARDOT_USER, password=PARDOT_PASSWORD, user_key=PARDOT_USER_KEY) + self.pardot.authenticate() + + self.email_address = 'parrot@harbles.com' + self.first_name = 'Pickles' + self.last_name = 'Zardnif' + + # Make sure there isn't an existing prospect in the test account. + try: + self.pardot.prospects.delete_by_email(email=self.email_address) + except PardotAPIError as e: + # Error code 4 is raised if the prospect doesn't exist. + if e.err_code != 4: + raise e + + def tearDown(self): + try: + self.pardot.prospects.delete_by_email(email=self.email_address) + except PardotAPIError as e: + # Error code 4 is raised if the prospect doesn't exist. + if e.err_code != 4: + raise e + + def _check_prospect(self, prospect): + self.assertEquals(self.email_address, prospect['email']) + self.assertEquals(self.first_name, prospect['first_name']) + self.assertEquals(self.last_name, prospect['last_name']) + + def test_create_and_read(self): + with self.assertRaises(PardotAPIArgumentError): + results = self.pardot.prospects.create_by_email(first_name=self.first_name, last_name=self.last_name) + + results = self.pardot.prospects.create_by_email(email=self.email_address, first_name=self.first_name, last_name=self.last_name) + + prospect = results['prospect'] + self._check_prospect(prospect) + + with self.assertRaises(PardotAPIArgumentError): + results = self.pardot.prospects.read_by_id(email='test@test.com') + + results = self.pardot.prospects.read_by_id(id=prospect['id']) + self._check_prospect(results['prospect']) + + with self.assertRaises(PardotAPIArgumentError): + results = self.pardot.prospects.read_by_email(id='test') + + results = self.pardot.prospects.read_by_email(email=prospect['email']) + self._check_prospect(results['prospect']) + + def test_update(self): + results = self.pardot.prospects.create_by_email(email=self.email_address, first_name=self.first_name, last_name='McGee') + + prospect = results['prospect'] + self.assertEquals('McGee', prospect['last_name']) + + with self.assertRaises(PardotAPIArgumentError): + self.pardot.prospects.update_by_email(id=prospect['id'], last_name='Ferdle') + + self.pardot.prospects.update_by_email(email=self.email_address, last_name='Ferdle') + + results = self.pardot.prospects.read_by_id(prospect['id']) + self.assertEquals('Ferdle', results['prospect']['last_name']) + + with self.assertRaises(PardotAPIArgumentError): + self.pardot.prospects.update_by_id(email=self.email_address, last_name='Ferdle') + + self.pardot.prospects.update_by_id(id=prospect['id'], last_name='Klampett') + + results = self.pardot.prospects.read_by_id(prospect['id']) + self.assertEquals('Klampett', results['prospect']['last_name']) + + def test_upsert(self): + with self.assertRaises(PardotAPIArgumentError): + results = self.pardot.prospects.upsert_by_email(first_name=self.first_name, last_name=self.last_name) + + results = self.pardot.prospects.upsert_by_email(email=self.email_address, first_name=self.first_name, last_name=self.last_name) + + prospect = results['prospect'] + self._check_prospect(prospect) + + with self.assertRaises(PardotAPIArgumentError): + self.pardot.prospects.upsert_by_id(email=prospect['id'], last_name='Ferdle') + + self.pardot.prospects.upsert_by_email(email=self.email_address, first_name=self.first_name, last_name='Ferdle') + + results = self.pardot.prospects.read_by_email(prospect['email']) + self.assertEquals('Ferdle', results['prospect']['last_name']) + self.assertEquals(prospect['id'], results['prospect']['id']) + + def test_delete(self): + results = self.pardot.prospects.create_by_email(email=self.email_address, first_name=self.first_name, last_name=self.last_name) + prospect = results['prospect'] + + with self.assertRaises(PardotAPIArgumentError): + self.pardot.prospects.delete_by_email(id=prospect['id']) + + with self.assertRaises(PardotAPIArgumentError): + self.pardot.prospects.delete_by_id(email=prospect['email']) + + results = self.pardot.prospects.read_by_id(prospect['id']) + self.pardot.prospects.delete_by_id(id=prospect['id']) + with self.assertRaises(PardotAPIError): + results = self.pardot.prospects.read_by_id(prospect['id']) diff --git a/pypardot/objects_v3/users.py b/pypardot/objects_v3/users.py new file mode 100644 index 0000000..1205e31 --- /dev/null +++ b/pypardot/objects_v3/users.py @@ -0,0 +1,50 @@ +class Users(object): + """ + A class to query and use Pardot users. + User field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#user + """ + + def __init__(self, client): + self.client = client + + def query(self, **kwargs): + """ + Returns the users matching the specified criteria parameters. + Supported search criteria: http://developer.pardot.com/kb/api-version-3/users/#supported-search-criteria + """ + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['users'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['user'] = [] + elif result['total_results'] == 1: + result['user'] = [result['user']] + + return result + + def read_by_id(self, id=None, **kwargs): + """ + Returns the data for the user specified by . is the Pardot ID of the target user.""" + response = self._post(path='/do/read/id/{id}'.format(id=id), params=kwargs) + return response + + def read_by_email(self, email=None, **kwargs): + """ + Returns the data for the user specified by . is the email address of the target user.""" + response = self._post(path='/do/read/email/{email}'.format(email=email), params=kwargs) + return response + + def _get(self, object_name='user', path=None, params=None): + """GET requests for the User object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='user', path=None, params=None): + """POST requests for the User object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/visitoractivities.py b/pypardot/objects_v3/visitoractivities.py new file mode 100644 index 0000000..fd08d4b --- /dev/null +++ b/pypardot/objects_v3/visitoractivities.py @@ -0,0 +1,45 @@ +class VisitorActivities(object): + """ + A class to query and use Pardot visitor activities. + Visitor Activity field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#visitor-activity + """ + + def __init__(self, client): + self.client = client + + def query(self, **kwargs): + """ + Returns the visitor activities matching the specified criteria parameters. + Supported search criteria: http://developer.pardot.com/kb/api-version-3/visitor-activities/#supported-search-criteria + """ + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['visitor_activity'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['visitor_activity'] = [] + elif result['total_results'] == 1: + result['visitor_activity'] = [result['visitor_activity']] + + return result + + def read(self, id=None, **kwargs): + """ + Returns the data for the visitor activity specified by . is the Pardot ID for the target visitor activity. + """ + response = self._post(path='/do/read/id/{id}'.format(id=id), params=kwargs) + return response + + def _get(self, object_name='visitorActivity', path=None, params=None): + """GET requests for the Visitor Activity object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='visitorActivity', path=None, params=None): + """POST requests for the Visitor Activity object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/visitors.py b/pypardot/objects_v3/visitors.py new file mode 100644 index 0000000..3401fb2 --- /dev/null +++ b/pypardot/objects_v3/visitors.py @@ -0,0 +1,55 @@ +class Visitors(object): + """ + A class to query and use Pardot visitors. + Visitor field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#visitor + """ + + def __init__(self, client): + self.client = client + + def query(self, **kwargs): + """ + Returns the visitors matching the specified criteria parameters. + Supported search criteria: http://developer.pardot.com/kb/api-version-3/visitors/#supported-search-criteria + """ + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['visitor'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['visitor'] = [] + elif result['total_results'] == 1: + result['visitor'] = [result['visitor']] + + return result + + def assign(self, id=None, **kwargs): + """ + Assigns or reassigns the visitor specified by to a specified prospect. One (and only one) of the following + parameters must be provided to identify the target prospect: or . Returns an + updated version of the visitor. + """ + response = self._post(path='/do/assign/id/{id}'.format(id=id), params=kwargs) + return response + + def read(self, id=None, **kwargs): + """ + Returns the data for the visitor specified by , including associated visitor activities, identified + company data, and visitor referrers. is the Pardot ID for the target visitor. + """ + response = self._post(path='/do/read/id/{id}'.format(id=id), params=kwargs) + return response + + def _get(self, object_name='visitor', path=None, params=None): + """GET requests for the Visitor object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='visitor', path=None, params=None): + """POST requests for the Visitor object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/pypardot/objects_v3/visits.py b/pypardot/objects_v3/visits.py new file mode 100644 index 0000000..b5d3f96 --- /dev/null +++ b/pypardot/objects_v3/visits.py @@ -0,0 +1,76 @@ +class Visits(object): + """ + A class to query and use Pardot visits. + Visit field reference: http://developer.pardot.com/kb/api-version-3/object-field-references/#visit + """ + + def __init__(self, client): + self.client = client + + def query_by_ids(self, ids=None, **kwargs): + """Returns the visits matching the given . The should be comma separated integers (no spaces).""" + kwargs['ids'] = ids.replace(' ', '') + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['visit'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['visit'] = [] + elif result['total_results'] == 1: + result['visit'] = [result['visit']] + + return result + + def query_by_visitor_ids(self, visitor_ids=None, **kwargs): + """ + Returns the visits matching the given . The should be comma separated integers + (no spaces). + """ + kwargs['visitor_ids'] = visitor_ids.replace(' ', '') + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['visit'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['visit'] = [] + elif result['total_results'] == 1: + result['visit'] = [result['visit']] + + return result + + def query_by_prospect_ids(self, prospect_ids=None, **kwargs): + """ + Returns the visits matching the given . The should be comma separated integers + (no spaces). + """ + kwargs['prospect_ids'] = prospect_ids.replace(' ', '') + response = self._get(path='/do/query', params=kwargs) + + # Ensure result['visit'] is a list, no matter what. + result = response.get('result') + if result['total_results'] == 0: + result['visit'] = [] + elif result['total_results'] == 1: + result['visit'] = [result['visit']] + + return result + + def read(self, id=None, **kwargs): + """ + Returns the data for the visit specified by . is the Pardot ID of the target visit.""" + response = self._post(path='/do/read/id/{id}'.format(id=id), params=kwargs) + return response + + def _get(self, object_name='visit', path=None, params=None): + """GET requests for the Visit object.""" + if params is None: + params = {} + response = self.client.get(object_name=object_name, path=path, params=params) + return response + + def _post(self, object_name='visit', path=None, params=None): + """POST requests for the Visit object.""" + if params is None: + params = {} + response = self.client.post(object_name=object_name, path=path, params=params) + return response diff --git a/setup.py b/setup.py index 16f1efc..930f351 100644 --- a/setup.py +++ b/setup.py @@ -10,6 +10,6 @@ description="API wrapper for APIv4 of Pardot marketing automation software.", keywords="pardot", url="https://github.com/mneedham91/PyPardot4", - packages=['pypardot', 'pypardot.objects'], + packages=['pypardot', 'pypardot.objects', 'pypardot.objects_v3'], install_requires=['requests'], )