diff --git a/.travis.yml b/.travis.yml index a5500fa..cdd4654 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ python: - 3.3 - 3.4 - 3.5 + - 3.6 script: - coverage run --source=createsend nosetests.py - coverage report diff --git a/createsend/__init__.py b/createsend/__init__.py index 8dbaf2d..4c76c6b 100644 --- a/createsend/__init__.py +++ b/createsend/__init__.py @@ -1,11 +1,20 @@ -from .createsend import * -from .client import Client -from .template import Template -from .list import List -from .segment import Segment -from .subscriber import Subscriber -from .campaign import Campaign -from .person import Person -from .administrator import Administrator -from .transactional import Transactional -from . import utils +# -*- coding: utf-8 -*- +__title__ = 'createsend-python' +__author__ = 'Dylan Stein' +__license__ = 'MIT' +__copyright__ = 'Copyright 2017' + + +from createsend.createsend import * +from createsend.client import Client +from createsend.template import Template +from createsend.list import List +from createsend.segment import Segment +from createsend.subscriber import Subscriber +from createsend.campaign import Campaign +from createsend.person import Person +from createsend.administrator import Administrator +from createsend.transactional import Transactional +from createsend import utils + +from createsend.version import __version__ diff --git a/createsend/administrator.py b/createsend/administrator.py index b5a9baa..1ee7350 100644 --- a/createsend/administrator.py +++ b/createsend/administrator.py @@ -1,43 +1,45 @@ try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase, BadRequest -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase +from createsend.utils import json_to_py + class Administrator(CreateSendBase): - """Represents an administrator and associated functionality.""" + """Represents an administrator and associated functionality.""" - def __init__(self, auth=None, email_address=None): - self.email_address = email_address - super(Administrator, self).__init__(auth) + def __init__(self, auth=None, email_address=None): + self.email_address = email_address + super(Administrator, self).__init__(auth) - def get(self, email_address=None): - """Gets an administrator by email address.""" - params = { "email": email_address or self.email_address } - response = self._get("/admins.json", params=params) - return json_to_py(response) + def get(self, email_address=None): + """Gets an administrator by email address.""" + params = {"email": email_address or self.email_address} + response = self._get("/admins.json", params=params) + return json_to_py(response) - def add(self, email_address, name): - """Adds an administrator to an account.""" - body = { - "EmailAddress": email_address, - "Name": name} - response = self._post("/admins.json", json.dumps(body)) - return json_to_py(response) + def add(self, email_address, name): + """Adds an administrator to an account.""" + body = { + "EmailAddress": email_address, + "Name": name} + response = self._post("/admins.json", json.dumps(body)) + return json_to_py(response) - def update(self, new_email_address, name): - """Updates the details for an administrator.""" - params = { "email": self.email_address } - body = { - "EmailAddress": new_email_address, - "Name": name} - response = self._put("/admins.json", - body=json.dumps(body), params=params) - # Update self.email_address, so this object can continue to be used reliably - self.email_address = new_email_address + def update(self, new_email_address, name): + """Updates the details for an administrator.""" + params = {"email": self.email_address} + body = { + "EmailAddress": new_email_address, + "Name": name} + response = self._put("/admins.json", + body=json.dumps(body), params=params) + # Update self.email_address, so this object can continue to be used + # reliably + self.email_address = new_email_address - def delete(self): - """Deletes the administrator from the account.""" - params = { "email": self.email_address } - response = self._delete("/admins.json", params=params) + def delete(self): + """Deletes the administrator from the account.""" + params = {"email": self.email_address} + response = self._delete("/admins.json", params=params) diff --git a/createsend/campaign.py b/createsend/campaign.py index bffe790..2b3efae 100644 --- a/createsend/campaign.py +++ b/createsend/campaign.py @@ -1,190 +1,193 @@ try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase +from createsend.utils import json_to_py + class Campaign(CreateSendBase): - """Represents a campaign and provides associated functionality.""" - - def __init__(self, auth=None, campaign_id=None): - self.campaign_id = campaign_id - super(Campaign, self).__init__(auth) - - def create(self, client_id, subject, name, from_name, from_email, reply_to, html_url, - text_url, list_ids, segment_ids): - """Creates a new campaign for a client. - - :param client_id: String representing the ID of the client for whom the - campaign will be created. - :param subject: String representing the subject of the campaign. - :param name: String representing the name of the campaign. - :param from_name: String representing the from name for the campaign. - :param from_email: String representing the from address for the campaign. - :param reply_to: String representing the reply-to address for the campaign. - :param html_url: String representing the URL for the campaign HTML content. - :param text_url: String representing the URL for the campaign text content. - Note that text_url is optional and if None or an empty string, text - content will be automatically generated from the HTML content. - :param list_ids: Array of Strings representing the IDs of the lists to - which the campaign will be sent. - :param segment_ids: Array of Strings representing the IDs of the segments to - which the campaign will be sent. - :returns String representing the ID of the newly created campaign. - """ - body = { - "Subject": subject, - "Name": name, - "FromName": from_name, - "FromEmail": from_email, - "ReplyTo": reply_to, - "HtmlUrl": html_url, - "TextUrl": text_url, - "ListIDs": list_ids, - "SegmentIDs": segment_ids } - response = self._post("/campaigns/%s.json" % client_id, json.dumps(body)) - self.campaign_id = json_to_py(response) - return self.campaign_id - - def create_from_template(self, client_id, subject, name, from_name, - from_email, reply_to, list_ids, segment_ids, template_id, template_content): - """Creates a new campaign for a client, from a template. - - :param client_id: String representing the ID of the client for whom the - campaign will be created. - :param subject: String representing the subject of the campaign. - :param name: String representing the name of the campaign. - :param from_name: String representing the from name for the campaign. - :param from_email: String representing the from address for the campaign. - :param reply_to: String representing the reply-to address for the campaign. - :param list_ids: Array of Strings representing the IDs of the lists to - which the campaign will be sent. - :param segment_ids: Array of Strings representing the IDs of the segments to - which the campaign will be sent. - :param template_id: String representing the ID of the template on which - the campaign will be based. - :param template_content: Hash representing the content to be used for the - editable areas of the template. See documentation at - campaignmonitor.com/api/campaigns/#creating_a_campaign_from_template - for full details of template content format. - :returns String representing the ID of the newly created campaign. - """ - body = { - "Subject": subject, - "Name": name, - "FromName": from_name, - "FromEmail": from_email, - "ReplyTo": reply_to, - "ListIDs": list_ids, - "SegmentIDs": segment_ids, - "TemplateID": template_id, - "TemplateContent": template_content } - response = self._post("/campaigns/%s/fromtemplate.json" % client_id, json.dumps(body)) - self.campaign_id = json_to_py(response) - return self.campaign_id - - def send_preview(self, recipients, personalize="fallback"): - """Sends a preview of this campaign.""" - body = { - "PreviewRecipients": [ recipients ] if isinstance(recipients, str) else recipients, - "Personalize": personalize } - response = self._post(self.uri_for("sendpreview"), json.dumps(body)) - - def send(self, confirmation_email, send_date="immediately"): - """Sends this campaign.""" - body = { - "ConfirmationEmail": confirmation_email, - "SendDate": send_date } - response = self._post(self.uri_for("send"), json.dumps(body)) - - def unschedule(self): - """Unschedules this campaign if it is currently scheduled.""" - response = self._post(self.uri_for("unschedule"), json.dumps({})) - - def delete(self): - """Deletes this campaign.""" - response = self._delete("/campaigns/%s.json" % self.campaign_id) - - def summary(self): - """Gets a summary of this campaign""" - response = self._get(self.uri_for("summary")) - return json_to_py(response) - - def email_client_usage(self): - """Gets the email clients that subscribers used to open the campaign""" - response = self._get(self.uri_for("emailclientusage")) - return json_to_py(response) - - def lists_and_segments(self): - """Retrieves the lists and segments to which this campaaign will be (or was) sent.""" - response = self._get(self.uri_for("listsandsegments")) - return json_to_py(response) - - def recipients(self, page=1, page_size=1000, order_field="email", order_direction="asc"): - """Retrieves the recipients of this campaign.""" - params = { - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("recipients"), params=params) - return json_to_py(response) - - def opens(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): - """Retrieves the opens for this campaign.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("opens"), params=params) - return json_to_py(response) - - def clicks(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): - """Retrieves the subscriber clicks for this campaign.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("clicks"), params=params) - return json_to_py(response) - - def unsubscribes(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): - """Retrieves the unsubscribes for this campaign.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("unsubscribes"), params=params) - return json_to_py(response) - - def spam(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): - """Retrieves the spam complaints for this campaign.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("spam"), params=params) - return json_to_py(response) - - def bounces(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): - """Retrieves the bounces for this campaign.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("bounces"), params=params) - return json_to_py(response) - - def uri_for(self, action): - return "/campaigns/%s/%s.json" % (self.campaign_id, action) + """Represents a campaign and provides associated functionality.""" + + def __init__(self, auth=None, campaign_id=None): + self.campaign_id = campaign_id + super(Campaign, self).__init__(auth) + + def create(self, client_id, subject, name, from_name, from_email, reply_to, html_url, + text_url, list_ids, segment_ids): + """Creates a new campaign for a client. + + :param client_id: String representing the ID of the client for whom the + campaign will be created. + :param subject: String representing the subject of the campaign. + :param name: String representing the name of the campaign. + :param from_name: String representing the from name for the campaign. + :param from_email: String representing the from address for the campaign. + :param reply_to: String representing the reply-to address for the campaign. + :param html_url: String representing the URL for the campaign HTML content. + :param text_url: String representing the URL for the campaign text content. + Note that text_url is optional and if None or an empty string, text + content will be automatically generated from the HTML content. + :param list_ids: Array of Strings representing the IDs of the lists to + which the campaign will be sent. + :param segment_ids: Array of Strings representing the IDs of the segments to + which the campaign will be sent. + :returns String representing the ID of the newly created campaign. + """ + body = { + "Subject": subject, + "Name": name, + "FromName": from_name, + "FromEmail": from_email, + "ReplyTo": reply_to, + "HtmlUrl": html_url, + "TextUrl": text_url, + "ListIDs": list_ids, + "SegmentIDs": segment_ids} + response = self._post("/campaigns/%s.json" % + client_id, json.dumps(body)) + self.campaign_id = json_to_py(response) + return self.campaign_id + + def create_from_template(self, client_id, subject, name, from_name, + from_email, reply_to, list_ids, segment_ids, template_id, template_content): + """Creates a new campaign for a client, from a template. + + :param client_id: String representing the ID of the client for whom the + campaign will be created. + :param subject: String representing the subject of the campaign. + :param name: String representing the name of the campaign. + :param from_name: String representing the from name for the campaign. + :param from_email: String representing the from address for the campaign. + :param reply_to: String representing the reply-to address for the campaign. + :param list_ids: Array of Strings representing the IDs of the lists to + which the campaign will be sent. + :param segment_ids: Array of Strings representing the IDs of the segments to + which the campaign will be sent. + :param template_id: String representing the ID of the template on which + the campaign will be based. + :param template_content: Hash representing the content to be used for the + editable areas of the template. See documentation at + campaignmonitor.com/api/campaigns/#creating_a_campaign_from_template + for full details of template content format. + :returns String representing the ID of the newly created campaign. + """ + body = { + "Subject": subject, + "Name": name, + "FromName": from_name, + "FromEmail": from_email, + "ReplyTo": reply_to, + "ListIDs": list_ids, + "SegmentIDs": segment_ids, + "TemplateID": template_id, + "TemplateContent": template_content} + response = self._post("/campaigns/%s/fromtemplate.json" % + client_id, json.dumps(body)) + self.campaign_id = json_to_py(response) + return self.campaign_id + + def send_preview(self, recipients, personalize="fallback"): + """Sends a preview of this campaign.""" + body = { + "PreviewRecipients": [recipients] if isinstance(recipients, str) else recipients, + "Personalize": personalize} + response = self._post(self.uri_for("sendpreview"), json.dumps(body)) + + def send(self, confirmation_email, send_date="immediately"): + """Sends this campaign.""" + body = { + "ConfirmationEmail": confirmation_email, + "SendDate": send_date} + response = self._post(self.uri_for("send"), json.dumps(body)) + + def unschedule(self): + """Unschedules this campaign if it is currently scheduled.""" + response = self._post(self.uri_for("unschedule"), json.dumps({})) + + def delete(self): + """Deletes this campaign.""" + response = self._delete("/campaigns/%s.json" % self.campaign_id) + + def summary(self): + """Gets a summary of this campaign""" + response = self._get(self.uri_for("summary")) + return json_to_py(response) + + def email_client_usage(self): + """Gets the email clients that subscribers used to open the campaign""" + response = self._get(self.uri_for("emailclientusage")) + return json_to_py(response) + + def lists_and_segments(self): + """Retrieves the lists and segments to which this campaaign will be (or was) sent.""" + response = self._get(self.uri_for("listsandsegments")) + return json_to_py(response) + + def recipients(self, page=1, page_size=1000, order_field="email", order_direction="asc"): + """Retrieves the recipients of this campaign.""" + params = { + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("recipients"), params=params) + return json_to_py(response) + + def opens(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): + """Retrieves the opens for this campaign.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("opens"), params=params) + return json_to_py(response) + + def clicks(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): + """Retrieves the subscriber clicks for this campaign.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("clicks"), params=params) + return json_to_py(response) + + def unsubscribes(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): + """Retrieves the unsubscribes for this campaign.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("unsubscribes"), params=params) + return json_to_py(response) + + def spam(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): + """Retrieves the spam complaints for this campaign.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("spam"), params=params) + return json_to_py(response) + + def bounces(self, date="", page=1, page_size=1000, order_field="date", order_direction="asc"): + """Retrieves the bounces for this campaign.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("bounces"), params=params) + return json_to_py(response) + + def uri_for(self, action): + return "/campaigns/%s/%s.json" % (self.campaign_id, action) diff --git a/createsend/client.py b/createsend/client.py index 726304e..5053efa 100644 --- a/createsend/client.py +++ b/createsend/client.py @@ -1,168 +1,171 @@ try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase +from createsend.utils import json_to_py + class Client(CreateSendBase): - """Represents a client and associated functionality.""" - - def __init__(self, auth=None, client_id=None): - self.client_id = client_id - super(Client, self).__init__(auth) - - def create(self, company, timezone, country): - """Creates a client.""" - - body = { - "CompanyName": company, - "TimeZone": timezone, - "Country": country } - response = self._post("/clients.json", json.dumps(body)) - self.client_id = json_to_py(response) - return self.client_id - - def details(self): - """Gets the details of this client.""" - response = self._get("/clients/%s.json" % self.client_id) - return json_to_py(response) - - def campaigns(self): - """Gets the sent campaigns belonging to this client.""" - response = self._get(self.uri_for("campaigns")) - return json_to_py(response) - - def scheduled(self): - """Gets the currently scheduled campaigns belonging to this client.""" - response = self._get(self.uri_for("scheduled")) - return json_to_py(response) - - def drafts(self): - """Gets the draft campaigns belonging to this client.""" - response = self._get(self.uri_for("drafts")) - return json_to_py(response) - - def lists(self): - """Gets the subscriber lists belonging to this client.""" - response = self._get(self.uri_for("lists")) - return json_to_py(response) - - def lists_for_email(self, email_address): - """Gets the lists across a client to which a subscriber with a particular - email address belongs.""" - params = { "email": email_address } - response = self._get(self.uri_for("listsforemail"), params=params) - return json_to_py(response) - - def segments(self): - """Gets the segments belonging to this client.""" - response = self._get(self.uri_for("segments")) - return json_to_py(response) - - def suppressionlist(self, page=1, page_size=1000, order_field="email", order_direction="asc"): - """Gets this client's suppression list.""" - params = { - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("suppressionlist"), params=params) - return json_to_py(response) - - def suppress(self, email): - """Adds email addresses to a client's suppression list""" - body = { - "EmailAddresses": [ email ] if isinstance(email, str) else email } - response = self._post(self.uri_for("suppress"), json.dumps(body)) - - def unsuppress(self, email): - """Unsuppresses an email address by removing it from the the client's - suppression list""" - params = { "email": email } - response = self._put(self.uri_for("unsuppress"), body=" ", params=params) - - def templates(self): - """Gets the templates belonging to this client.""" - response = self._get(self.uri_for("templates")) - return json_to_py(response) - - def set_basics(self, company, timezone, country): - body = { - "CompanyName": company, - "TimeZone": timezone, - "Country": country } - response = self._put(self.uri_for('setbasics'), json.dumps(body)) - - def set_payg_billing(self, currency, can_purchase_credits, client_pays, markup_percentage, - markup_on_delivery=0, markup_per_recipient=0, markup_on_design_spam_test=0): - """Sets the PAYG billing settings for this client.""" - body = { - "Currency": currency, - "CanPurchaseCredits": can_purchase_credits, - "ClientPays": client_pays, - "MarkupPercentage": markup_percentage, - "MarkupOnDelivery": markup_on_delivery, - "MarkupPerRecipient": markup_per_recipient, - "MarkupOnDesignSpamTest": markup_on_design_spam_test } - response = self._put(self.uri_for('setpaygbilling'), json.dumps(body)) - - def set_monthly_billing(self, currency, client_pays, markup_percentage, monthly_scheme = None): - """Sets the monthly billing settings for this client.""" - body = { - "Currency": currency, - "ClientPays": client_pays, - "MarkupPercentage": markup_percentage } - - if monthly_scheme is not None: - body["MonthlyScheme"] = monthly_scheme - - response = self._put(self.uri_for('setmonthlybilling'), json.dumps(body)) - - def transfer_credits(self, credits, can_use_my_credits_when_they_run_out): - """Transfer credits to or from this client. - - :param credits: An Integer representing the number of credits to transfer. - This value may be either positive if you want to allocate credits from - your account to the client, or negative if you want to deduct credits - from the client back into your account. - :param can_use_my_credits_when_they_run_out: A Boolean value representing - which, if set to true, will allow the client to continue sending using - your credits or payment details once they run out of credits, and if - set to false, will prevent the client from using your credits to - continue sending until you allocate more credits to them. - :returns: An object of the following form representing the result: - { - AccountCredits # Integer representing credits in your account now - ClientCredits # Integer representing credits in this client's - account now - } - """ - body = { - "Credits": credits, - "CanUseMyCreditsWhenTheyRunOut": can_use_my_credits_when_they_run_out } - response = self._post(self.uri_for('credits'), json.dumps(body)) - return json_to_py(response) - - def people(self): - """gets people associated with the client""" - response = self._get(self.uri_for('people')) - return json_to_py(response) - - def get_primary_contact(self): - """retrieves the primary contact for this client""" - response = self._get(self.uri_for('primarycontact')) - return json_to_py(response) - - def set_primary_contact(self, email): - """assigns the primary contact for this client""" - params = { "email": email } - response = self._put(self.uri_for('primarycontact'), params = params) - return json_to_py(response) - - def delete(self): - """Deletes this client.""" - response = self._delete("/clients/%s.json" % self.client_id) - - def uri_for(self, action): - return "/clients/%s/%s.json" % (self.client_id, action) + """Represents a client and associated functionality.""" + + def __init__(self, auth=None, client_id=None): + self.client_id = client_id + super(Client, self).__init__(auth) + + def create(self, company, timezone, country): + """Creates a client.""" + + body = { + "CompanyName": company, + "TimeZone": timezone, + "Country": country} + response = self._post("/clients.json", json.dumps(body)) + self.client_id = json_to_py(response) + return self.client_id + + def details(self): + """Gets the details of this client.""" + response = self._get("/clients/%s.json" % self.client_id) + return json_to_py(response) + + def campaigns(self): + """Gets the sent campaigns belonging to this client.""" + response = self._get(self.uri_for("campaigns")) + return json_to_py(response) + + def scheduled(self): + """Gets the currently scheduled campaigns belonging to this client.""" + response = self._get(self.uri_for("scheduled")) + return json_to_py(response) + + def drafts(self): + """Gets the draft campaigns belonging to this client.""" + response = self._get(self.uri_for("drafts")) + return json_to_py(response) + + def lists(self): + """Gets the subscriber lists belonging to this client.""" + response = self._get(self.uri_for("lists")) + return json_to_py(response) + + def lists_for_email(self, email_address): + """Gets the lists across a client to which a subscriber with a particular + email address belongs.""" + params = {"email": email_address} + response = self._get(self.uri_for("listsforemail"), params=params) + return json_to_py(response) + + def segments(self): + """Gets the segments belonging to this client.""" + response = self._get(self.uri_for("segments")) + return json_to_py(response) + + def suppressionlist(self, page=1, page_size=1000, order_field="email", order_direction="asc"): + """Gets this client's suppression list.""" + params = { + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("suppressionlist"), params=params) + return json_to_py(response) + + def suppress(self, email): + """Adds email addresses to a client's suppression list""" + body = { + "EmailAddresses": [email] if isinstance(email, str) else email} + response = self._post(self.uri_for("suppress"), json.dumps(body)) + + def unsuppress(self, email): + """Unsuppresses an email address by removing it from the the client's + suppression list""" + params = {"email": email} + response = self._put(self.uri_for("unsuppress"), + body=" ", params=params) + + def templates(self): + """Gets the templates belonging to this client.""" + response = self._get(self.uri_for("templates")) + return json_to_py(response) + + def set_basics(self, company, timezone, country): + body = { + "CompanyName": company, + "TimeZone": timezone, + "Country": country} + response = self._put(self.uri_for('setbasics'), json.dumps(body)) + + def set_payg_billing(self, currency, can_purchase_credits, client_pays, markup_percentage, + markup_on_delivery=0, markup_per_recipient=0, markup_on_design_spam_test=0): + """Sets the PAYG billing settings for this client.""" + body = { + "Currency": currency, + "CanPurchaseCredits": can_purchase_credits, + "ClientPays": client_pays, + "MarkupPercentage": markup_percentage, + "MarkupOnDelivery": markup_on_delivery, + "MarkupPerRecipient": markup_per_recipient, + "MarkupOnDesignSpamTest": markup_on_design_spam_test} + response = self._put(self.uri_for('setpaygbilling'), json.dumps(body)) + + def set_monthly_billing(self, currency, client_pays, markup_percentage, monthly_scheme=None): + """Sets the monthly billing settings for this client.""" + body = { + "Currency": currency, + "ClientPays": client_pays, + "MarkupPercentage": markup_percentage} + + if monthly_scheme is not None: + body["MonthlyScheme"] = monthly_scheme + + response = self._put(self.uri_for( + 'setmonthlybilling'), json.dumps(body)) + + def transfer_credits(self, credits, can_use_my_credits_when_they_run_out): + """Transfer credits to or from this client. + + :param credits: An Integer representing the number of credits to transfer. + This value may be either positive if you want to allocate credits from + your account to the client, or negative if you want to deduct credits + from the client back into your account. + :param can_use_my_credits_when_they_run_out: A Boolean value representing + which, if set to true, will allow the client to continue sending using + your credits or payment details once they run out of credits, and if + set to false, will prevent the client from using your credits to + continue sending until you allocate more credits to them. + :returns: An object of the following form representing the result: + { + AccountCredits # Integer representing credits in your account now + ClientCredits # Integer representing credits in this client's + account now + } + """ + body = { + "Credits": credits, + "CanUseMyCreditsWhenTheyRunOut": can_use_my_credits_when_they_run_out} + response = self._post(self.uri_for('credits'), json.dumps(body)) + return json_to_py(response) + + def people(self): + """gets people associated with the client""" + response = self._get(self.uri_for('people')) + return json_to_py(response) + + def get_primary_contact(self): + """retrieves the primary contact for this client""" + response = self._get(self.uri_for('primarycontact')) + return json_to_py(response) + + def set_primary_contact(self, email): + """assigns the primary contact for this client""" + params = {"email": email} + response = self._put(self.uri_for('primarycontact'), params=params) + return json_to_py(response) + + def delete(self): + """Deletes this client.""" + response = self._delete("/clients/%s.json" % self.client_id) + + def uri_for(self, action): + return "/clients/%s/%s.json" % (self.client_id, action) diff --git a/createsend/createsend.py b/createsend/createsend.py index 316fa4c..da4bab1 100644 --- a/createsend/createsend.py +++ b/createsend/createsend.py @@ -6,294 +6,331 @@ from six import BytesIO from six.moves.urllib.parse import parse_qs, urlencode, urlparse try: - import json + import json except ImportError: - import simplejson as json -from .utils import VerifiedHTTPSConnection, json_to_py, get_faker + import simplejson as json +from createsend.utils import VerifiedHTTPSConnection, json_to_py, get_faker __version_info__ = ('4', '2', '1') __version__ = '.'.join(__version_info__) + class CreateSendError(Exception): - """Represents a CreateSend API error and contains specific data about the error.""" - def __init__(self, data): - self.data = data - def __str__(self): - # self.data should contain Code, Message and optionally ResultData - extra = ("\nExtra result data: %s" % self.data.ResultData) if hasattr(self.data, 'ResultData') else "" - return "The CreateSend API responded with the following error - %s: %s%s" % (self.data.Code, self.data.Message, extra) - -class ClientError(Exception): pass -class ServerError(Exception): pass -class BadRequest(CreateSendError): pass -class Unauthorized(CreateSendError): pass -class NotFound(ClientError): pass -class Unavailable(Exception): pass + """Represents a CreateSend API error and contains specific data about the error.""" + + def __init__(self, data): + self.data = data + + def __str__(self): + # self.data should contain Code, Message and optionally ResultData + extra = ("\nExtra result data: %s" % self.data.ResultData) if hasattr( + self.data, 'ResultData') else "" + return "The CreateSend API responded with the following error - %s: %s%s" % (self.data.Code, self.data.Message, extra) + + +class ClientError(Exception): + pass + + +class ServerError(Exception): + pass + + +class BadRequest(CreateSendError): + pass + + +class Unauthorized(CreateSendError): + pass + + +class NotFound(ClientError): + pass + + +class Unavailable(Exception): + pass + class ExpiredOAuthToken(Unauthorized): - """Raised for HTTP response code of 401, specifically when an OAuth - token has expired (Code: 121, Message: 'Expired OAuth Token')""" - pass + """Raised for HTTP response code of 401, specifically when an OAuth + token has expired (Code: 121, Message: 'Expired OAuth Token')""" + pass + class CreateSendBase(object): - auth_details = None - - def __init__(self, auth): - self.fake_web = False - self.auth(auth) - - def authorize_url(self, client_id, redirect_uri, scope, state=None): - """Get the authorization URL for your application, given the application's - client_id, redirect_uri, scope, and optional state data.""" - params = [ - ('client_id', client_id), - ('redirect_uri', redirect_uri), - ('scope', scope) - ] - if state: - params.append(('state', state)) - return "%s?%s" % (CreateSend.oauth_uri, urlencode(params)) - - def exchange_token(self, client_id, client_secret, redirect_uri, code): - """Exchange a provided OAuth code for an OAuth access token, 'expires in' - value and refresh token.""" - params = [ - ('grant_type', 'authorization_code'), - ('client_id', client_id), - ('client_secret', client_secret), - ('redirect_uri', redirect_uri), - ('code', code), - ] - response = self._post('', urlencode(params), - CreateSend.oauth_token_uri, "application/x-www-form-urlencoded") - access_token, expires_in, refresh_token = None, None, None - r = json_to_py(response) - if hasattr(r, 'error') and hasattr(r, 'error_description'): - err = "Error exchanging code for access token: " - err += "%s - %s" % (r.error, r.error_description) - raise Exception(err) - access_token, expires_in, refresh_token = r.access_token, r.expires_in, r.refresh_token - return [access_token, expires_in, refresh_token] - - def auth(self, auth): - """Authenticate with the Campaign Monitor API using either OAuth or - an API key. - - :param auth: A dictionary representing the authentication details to use. - This dictionary must take either of the following forms: - - {'access_token': 'your access token', 'refresh_token': 'your refresh token'} - - {'api_key': 'your api key'} - """ - self.auth_details = auth - - def refresh_token(self): - """Refresh an OAuth token given a refresh token.""" - if (not self.auth_details or - not 'refresh_token' in self.auth_details or - not self.auth_details['refresh_token']): - raise Exception("auth_details['refresh_token'] does not contain a refresh token.") - - refresh_token = self.auth_details['refresh_token'] - params = [ - ('grant_type', 'refresh_token'), - ('refresh_token', refresh_token) - ] - response = self._post('', urlencode(params), - CreateSend.oauth_token_uri, "application/x-www-form-urlencoded") - new_access_token, new_expires_in, new_refresh_token = None, None, None - r = json_to_py(response) - new_access_token, new_expires_in, new_refresh_token = r.access_token, r.expires_in, r.refresh_token - self.auth({ - 'access_token': new_access_token, - 'refresh_token': new_refresh_token}) - return [new_access_token, new_expires_in, new_refresh_token] - - def stub_request(self, expected_url, filename, status=None, body=None): - """Stub a web request for testing.""" - self.fake_web = True - self.faker = get_faker(expected_url, filename, status, body) - - def make_request(self, method, path, params={}, body="", username=None, - password=None, base_uri=None, content_type=None): - headers = { - 'User-Agent': CreateSend.user_agent, - 'Content-Type': 'application/json; charset=utf-8', - 'Accept-Encoding' : 'gzip, deflate' } - if content_type: - headers['Content-Type'] = content_type - parsed_base_uri = urlparse(CreateSend.base_uri if not base_uri else base_uri) - """username and password should only be set when it is intended that + auth_details = None + + def __init__(self, auth): + self.fake_web = False + self.auth(auth) + + def authorize_url(self, client_id, redirect_uri, scope, state=None): + """Get the authorization URL for your application, given the application's + client_id, redirect_uri, scope, and optional state data.""" + params = [ + ('client_id', client_id), + ('redirect_uri', redirect_uri), + ('scope', scope) + ] + if state: + params.append(('state', state)) + return "%s?%s" % (CreateSend.oauth_uri, urlencode(params)) + + def exchange_token(self, client_id, client_secret, redirect_uri, code): + """Exchange a provided OAuth code for an OAuth access token, 'expires in' + value and refresh token.""" + params = [ + ('grant_type', 'authorization_code'), + ('client_id', client_id), + ('client_secret', client_secret), + ('redirect_uri', redirect_uri), + ('code', code), + ] + response = self._post('', urlencode(params), + CreateSend.oauth_token_uri, "application/x-www-form-urlencoded") + access_token, expires_in, refresh_token = None, None, None + r = json_to_py(response) + if hasattr(r, 'error') and hasattr(r, 'error_description'): + err = "Error exchanging code for access token: " + err += "%s - %s" % (r.error, r.error_description) + raise Exception(err) + access_token, expires_in, refresh_token = r.access_token, r.expires_in, r.refresh_token + return [access_token, expires_in, refresh_token] + + def auth(self, auth): + """Authenticate with the Campaign Monitor API using either OAuth or + an API key. + + :param auth: A dictionary representing the authentication details to use. + This dictionary must take either of the following forms: + + {'access_token': 'your access token', 'refresh_token': 'your refresh token'} + + {'api_key': 'your api key'} + """ + self.auth_details = auth + + def refresh_token(self): + """Refresh an OAuth token given a refresh token.""" + if (not self.auth_details or + not 'refresh_token' in self.auth_details or + not self.auth_details['refresh_token']): + raise Exception( + "auth_details['refresh_token'] does not contain a refresh token.") + + refresh_token = self.auth_details['refresh_token'] + params = [ + ('grant_type', 'refresh_token'), + ('refresh_token', refresh_token) + ] + response = self._post('', urlencode(params), + CreateSend.oauth_token_uri, "application/x-www-form-urlencoded") + new_access_token, new_expires_in, new_refresh_token = None, None, None + r = json_to_py(response) + new_access_token, new_expires_in, new_refresh_token = r.access_token, r.expires_in, r.refresh_token + self.auth({ + 'access_token': new_access_token, + 'refresh_token': new_refresh_token}) + return [new_access_token, new_expires_in, new_refresh_token] + + def stub_request(self, expected_url, filename, status=None, body=None): + """Stub a web request for testing.""" + self.fake_web = True + self.faker = get_faker(expected_url, filename, status, body) + + def make_request(self, method, path, params={}, body="", username=None, + password=None, base_uri=None, content_type=None): + headers = { + 'User-Agent': CreateSend.user_agent, + 'Content-Type': 'application/json; charset=utf-8', + 'Accept-Encoding': 'gzip, deflate'} + if content_type: + headers['Content-Type'] = content_type + parsed_base_uri = urlparse( + CreateSend.base_uri if not base_uri else base_uri) + """username and password should only be set when it is intended that the default basic authentication mechanism using the API key be overridden (e.g. when using the apikey route with username and password).""" - if username and password: - headers['Authorization'] = "Basic %s" % base64.b64encode(("%s:%s" % (username, password)).encode()).decode() - elif self.auth_details: - if 'api_key' in self.auth_details and self.auth_details['api_key']: - headers['Authorization'] = "Basic %s" % base64.b64encode(("%s:x" % self.auth_details['api_key']).encode()).decode() - elif 'access_token' in self.auth_details and self.auth_details['access_token']: - headers['Authorization'] = "Bearer %s" % self.auth_details['access_token'] - self.headers = headers - - """If in fake web mode (i.e. self.stub_request has been called), + if username and password: + headers['Authorization'] = "Basic %s" % base64.b64encode( + ("%s:%s" % (username, password)).encode()).decode() + elif self.auth_details: + if 'api_key' in self.auth_details and self.auth_details['api_key']: + headers['Authorization'] = "Basic %s" % base64.b64encode( + ("%s:x" % self.auth_details['api_key']).encode()).decode() + elif 'access_token' in self.auth_details and self.auth_details['access_token']: + headers['Authorization'] = "Bearer %s" % self.auth_details[ + 'access_token'] + self.headers = headers + + """If in fake web mode (i.e. self.stub_request has been called), self.faker should be set, and this request should be treated as a fake.""" - if self.fake_web: - # Check that the actual url which would be requested matches self.faker.url. - actual_url = "https://%s%s" % (parsed_base_uri.netloc, self.build_url(parsed_base_uri, path, params)) - self.faker.actual_url = actual_url - def same_urls(url_a, url_b): - a = urlparse(url_a) - b = urlparse(url_b) - return (a.scheme == b.scheme and - a.netloc == b.netloc and - a.path == b.path and - a.params == b.params and - parse_qs(a.query) == parse_qs(b.query) and - a.fragment == b.fragment - ) - if not same_urls(self.faker.url, actual_url): - raise Exception("Faker's expected URL (%s) doesn't match actual URL (%s)" % (self.faker.url, actual_url)) - - self.faker.actual_body = body - def same_bodies(body_a, body_b): - return json.loads(body_a) == json.loads(body_b) - if self.faker.body is not None: - if not same_bodies(self.faker.body, body): - raise Exception("Faker's expected body (%s) doesn't match actual body (%s)" % (self.faker.body, body)) - - data = self.faker.open() if self.faker else '' - status = self.faker.status if (self.faker and self.faker.status) else 200 - return self.handle_response(status, data) - - c = VerifiedHTTPSConnection(parsed_base_uri.netloc) - c.request(method, self.build_url(parsed_base_uri, path, params), body, headers) - response = c.getresponse() - if response.getheader('content-encoding', '') == 'gzip': - data = gzip.GzipFile(fileobj=BytesIO(response.read())).read() - else: - data = response.read() - c.close() - return self.handle_response(response.status, data) - - def build_url(self, parsed_base_uri, path, params): - url = parsed_base_uri.path + path - if params and len(params) > 0: - url = (url + "?%s" % urlencode(params)) - return url - - def handle_response(self, status, data): - if status == 400: - raise BadRequest(json_to_py(data)) - elif status == 401: - json_data = json_to_py(data) - if json_data.Code == 121: - raise ExpiredOAuthToken(json_data) - raise Unauthorized(json_data) - elif status == 404: - raise NotFound() - elif status in range(400, 500): - raise ClientError() - elif status in range(500, 600): - raise ServerError() - return data - - def _get(self, path, params={}, username=None, password=None): - return self.make_request(path=path, method="GET", params=params, username=username, password=password) - - def _post(self, path, body="", base_uri=None, content_type=None): - return self.make_request(path=path, method="POST", body=body, - base_uri=base_uri, content_type=content_type) - - def _put(self, path, body="", params={}): - return self.make_request(path=path, method="PUT", params=params, body=body) - - def _delete(self, path, params={}): - return self.make_request(path=path, method="DELETE", params=params) + if self.fake_web: + # Check that the actual url which would be requested matches + # self.faker.url. + actual_url = "https://%s%s" % (parsed_base_uri.netloc, + self.build_url(parsed_base_uri, path, params)) + self.faker.actual_url = actual_url + + def same_urls(url_a, url_b): + a = urlparse(url_a) + b = urlparse(url_b) + return (a.scheme == b.scheme and + a.netloc == b.netloc and + a.path == b.path and + a.params == b.params and + parse_qs(a.query) == parse_qs(b.query) and + a.fragment == b.fragment + ) + if not same_urls(self.faker.url, actual_url): + raise Exception("Faker's expected URL (%s) doesn't match actual URL (%s)" % ( + self.faker.url, actual_url)) + + self.faker.actual_body = body + + def same_bodies(body_a, body_b): + return json.loads(body_a) == json.loads(body_b) + if self.faker.body is not None: + if not same_bodies(self.faker.body, body): + raise Exception("Faker's expected body (%s) doesn't match actual body (%s)" % ( + self.faker.body, body)) + + data = self.faker.open() if self.faker else '' + status = self.faker.status if ( + self.faker and self.faker.status) else 200 + return self.handle_response(status, data) + + c = VerifiedHTTPSConnection(parsed_base_uri.netloc) + c.request(method, self.build_url( + parsed_base_uri, path, params), body, headers) + response = c.getresponse() + if response.getheader('content-encoding', '') == 'gzip': + data = gzip.GzipFile(fileobj=BytesIO(response.read())).read() + else: + data = response.read() + c.close() + return self.handle_response(response.status, data) + + def build_url(self, parsed_base_uri, path, params): + url = parsed_base_uri.path + path + if params and len(params) > 0: + url = (url + "?%s" % urlencode(params)) + return url + + def handle_response(self, status, data): + if status == 400: + raise BadRequest(json_to_py(data)) + elif status == 401: + json_data = json_to_py(data) + if json_data.Code == 121: + raise ExpiredOAuthToken(json_data) + raise Unauthorized(json_data) + elif status == 404: + raise NotFound() + elif status in range(400, 500): + raise ClientError() + elif status in range(500, 600): + raise ServerError() + return data + + def _get(self, path, params={}, username=None, password=None): + return self.make_request(path=path, method="GET", params=params, username=username, password=password) + + def _post(self, path, body="", base_uri=None, content_type=None): + return self.make_request(path=path, method="POST", body=body, + base_uri=base_uri, content_type=content_type) + + def _put(self, path, body="", params={}): + return self.make_request(path=path, method="PUT", params=params, body=body) + + def _delete(self, path, params={}): + return self.make_request(path=path, method="DELETE", params=params) + class CreateSend(CreateSendBase): - """Provides high level CreateSend functionality/data you'll probably need.""" - base_uri = "https://api.createsend.com/api/v3.1" - oauth_uri = "https://api.createsend.com/oauth" - oauth_token_uri = "%s/token" % oauth_uri - platform = os.getenv('SERVER_SOFTWARE') or platform.platform() - default_user_agent = 'createsend-python-%s-%d.%d.%d-%s' % ( - __version__, sys.version_info[0], sys.version_info[1], - sys.version_info[2], platform) - # You can use `CreateSend.user_agent = "my user agent"` to override the - # default user agent string (CreateSend.default_user_agent) used when - # making API calls. - user_agent = default_user_agent - - def __init__(self, auth=None): - super(CreateSend, self).__init__(auth) - - def clients(self): - """Gets your clients.""" - response = self._get('/clients.json') - return json_to_py(response) - - def billing_details(self): - """Gets your billing details.""" - response = self._get('/billingdetails.json') - return json_to_py(response) - - def countries(self): - """Gets valid countries.""" - response = self._get('/countries.json') - return json_to_py(response) - - def systemdate(self): - """Gets the current date in your account's timezone.""" - response = self._get('/systemdate.json') - return json_to_py(response).SystemDate - - def timezones(self): - """Gets valid timezones.""" - response = self._get('/timezones.json') - return json_to_py(response) - - def administrators(self): - """Gets administrators associated with the account""" - response = self._get('/admins.json') - return json_to_py(response) - - def get_primary_contact(self): - """Retrieves the primary contact for this account""" - response = self._get('/primarycontact.json') - return json_to_py(response) - - def set_primary_contact(self, email): - """Assigns the primary contact for this account""" - params = { "email": email } - response = self._put('/primarycontact.json', params = params) - return json_to_py(response) - - def external_session_url(self, email, chrome, url, integrator_id, client_id): - """ - Get a URL which initiates a new external session for the user with the - given email. - Full details: http://www.campaignmonitor.com/api/account/#single_sign_on - - :param email: String The representing the email address of the - Campaign Monitor user for whom the login session should be created. - :param chrome: String representing which 'chrome' to display - Must be - either "all", "tabs", or "none". - :param url: String representing the URL to display once logged in. - e.g. "/subscribers/" - :param integrator_id: String representing the Integrator ID. You need to - contact Campaign Monitor support to get an Integrator ID. - :param client_id: String representing the Client ID of the client which - should be active once logged in to the Campaign Monitor account. - - :returns Object containing a single field SessionUrl which represents - the URL to initiate the external Campaign Monitor session. - """ - body = { - "Email": email, - "Chrome": chrome, - "Url": url, - "IntegratorID": integrator_id, - "ClientID": client_id } - response = self._put('/externalsession.json', json.dumps(body)) - return json_to_py(response) + """Provides high level CreateSend functionality/data you'll probably need.""" + base_uri = "https://api.createsend.com/api/v3.1" + oauth_uri = "https://api.createsend.com/oauth" + oauth_token_uri = "%s/token" % oauth_uri + platform = os.getenv('SERVER_SOFTWARE') or platform.platform() + default_user_agent = 'createsend-python-%s-%d.%d.%d-%s' % ( + __version__, sys.version_info[0], sys.version_info[1], + sys.version_info[2], platform) + # You can use `CreateSend.user_agent = "my user agent"` to override the + # default user agent string (CreateSend.default_user_agent) used when + # making API calls. + user_agent = default_user_agent + + def __init__(self, auth=None): + super(CreateSend, self).__init__(auth) + + def clients(self): + """Gets your clients.""" + response = self._get('/clients.json') + return json_to_py(response) + + def billing_details(self): + """Gets your billing details.""" + response = self._get('/billingdetails.json') + return json_to_py(response) + + def countries(self): + """Gets valid countries.""" + response = self._get('/countries.json') + return json_to_py(response) + + def systemdate(self): + """Gets the current date in your account's timezone.""" + response = self._get('/systemdate.json') + return json_to_py(response).SystemDate + + def timezones(self): + """Gets valid timezones.""" + response = self._get('/timezones.json') + return json_to_py(response) + + def administrators(self): + """Gets administrators associated with the account""" + response = self._get('/admins.json') + return json_to_py(response) + + def get_primary_contact(self): + """Retrieves the primary contact for this account""" + response = self._get('/primarycontact.json') + return json_to_py(response) + + def set_primary_contact(self, email): + """Assigns the primary contact for this account""" + params = {"email": email} + response = self._put('/primarycontact.json', params=params) + return json_to_py(response) + + def external_session_url(self, email, chrome, url, integrator_id, client_id): + """ + Get a URL which initiates a new external session for the user with the + given email. + Full details: http://www.campaignmonitor.com/api/account/#single_sign_on + + :param email: String The representing the email address of the + Campaign Monitor user for whom the login session should be created. + :param chrome: String representing which 'chrome' to display - Must be + either "all", "tabs", or "none". + :param url: String representing the URL to display once logged in. + e.g. "/subscribers/" + :param integrator_id: String representing the Integrator ID. You need to + contact Campaign Monitor support to get an Integrator ID. + :param client_id: String representing the Client ID of the client which + should be active once logged in to the Campaign Monitor account. + + :returns Object containing a single field SessionUrl which represents + the URL to initiate the external Campaign Monitor session. + """ + body = { + "Email": email, + "Chrome": chrome, + "Url": url, + "IntegratorID": integrator_id, + "ClientID": client_id} + response = self._put('/externalsession.json', json.dumps(body)) + return json_to_py(response) diff --git a/createsend/list.py b/createsend/list.py index 2e789a3..0e6d4c5 100644 --- a/createsend/list.py +++ b/createsend/list.py @@ -1,193 +1,199 @@ from six.moves.urllib.parse import quote try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase +from createsend.utils import json_to_py + class List(CreateSendBase): - """Represents a subscriber list and associated functionality.""" - - def __init__(self, auth=None, list_id=None): - self.list_id = list_id - super(List, self).__init__(auth) - - def create(self, client_id, title, unsubscribe_page, confirmed_opt_in, - confirmation_success_page, unsubscribe_setting="AllClientLists"): - """Creates a new list for a client.""" - body = { - "Title": title, - "UnsubscribePage": unsubscribe_page, - "ConfirmedOptIn": confirmed_opt_in, - "ConfirmationSuccessPage": confirmation_success_page, - "UnsubscribeSetting": unsubscribe_setting } - response = self._post("/lists/%s.json" % client_id, json.dumps(body)) - self.list_id = json_to_py(response) - return self.list_id - - def delete(self): - """Deletes this list.""" - response = self._delete("/lists/%s.json" % self.list_id) - - def create_custom_field(self, field_name, data_type, options=[], - visible_in_preference_center=True): - """Creates a new custom field for this list.""" - body = { - "FieldName": field_name, - "DataType": data_type, - "Options": options, - "VisibleInPreferenceCenter": visible_in_preference_center } - response = self._post(self.uri_for("customfields"), json.dumps(body)) - return json_to_py(response) - - def update_custom_field(self, custom_field_key, field_name, - visible_in_preference_center): - """Updates a custom field belonging to this list.""" - custom_field_key = quote(custom_field_key, '') - body = { - "FieldName": field_name, - "VisibleInPreferenceCenter": visible_in_preference_center } - response = self._put(self.uri_for("customfields/%s" % custom_field_key), json.dumps(body)) - return json_to_py(response) - - def delete_custom_field(self, custom_field_key): - """Deletes a custom field associated with this list.""" - custom_field_key = quote(custom_field_key, '') - response = self._delete("/lists/%s/customfields/%s.json" % - (self.list_id, custom_field_key)) - - def update_custom_field_options(self, custom_field_key, new_options, - keep_existing_options): - """Updates the options of a multi-optioned custom field on this list.""" - custom_field_key = quote(custom_field_key, '') - body = { - "Options": new_options, - "KeepExistingOptions": keep_existing_options } - response = self._put(self.uri_for("customfields/%s/options" % custom_field_key), json.dumps(body)) - - def details(self): - """Gets the details of this list.""" - response = self._get("/lists/%s.json" % self.list_id) - return json_to_py(response) - - def custom_fields(self): - """Gets the custom fields for this list.""" - response = self._get(self.uri_for("customfields")) - return json_to_py(response) - - def segments(self): - """Gets the segments for this list.""" - response = self._get(self.uri_for("segments")) - return json_to_py(response) - - def stats(self): - """Gets the stats for this list.""" - response = self._get(self.uri_for("stats")) - return json_to_py(response) - - def active(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): - """Gets the active subscribers for this list.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("active"), params=params) - return json_to_py(response) - - def unconfirmed(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): - """Gets the unconfirmed subscribers for this list.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("unconfirmed"), params=params) - return json_to_py(response) - - def bounced(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): - """Gets the bounced subscribers for this list.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("bounced"), params=params) - return json_to_py(response) - - def unsubscribed(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): - """Gets the unsubscribed subscribers for this list.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("unsubscribed"), params=params) - return json_to_py(response) - - def deleted(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): - """Gets the deleted subscribers for this list.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("deleted"), params=params) - return json_to_py(response) - - def update(self, title, unsubscribe_page, confirmed_opt_in, - confirmation_success_page, unsubscribe_setting="AllClientLists", - add_unsubscribes_to_supp_list=False, scrub_active_with_supp_list=False): - """Updates this list.""" - body = { - "Title": title, - "UnsubscribePage": unsubscribe_page, - "ConfirmedOptIn": confirmed_opt_in, - "ConfirmationSuccessPage": confirmation_success_page, - "UnsubscribeSetting": unsubscribe_setting, - "AddUnsubscribesToSuppList": add_unsubscribes_to_supp_list, - "ScrubActiveWithSuppList": scrub_active_with_supp_list } - response = self._put("/lists/%s.json" % self.list_id, json.dumps(body)) - - def webhooks(self): - """Gets the webhooks for this list.""" - response = self._get(self.uri_for("webhooks")) - return json_to_py(response) - - def create_webhook(self, events, url, payload_format): - """Creates a new webhook for the specified events (an array of strings). - Valid events are "Subscribe", "Deactivate", and "Update". - Valid payload formats are "json", and "xml".""" - body = { - "Events": events, - "Url": url, - "PayloadFormat": payload_format } - response = self._post(self.uri_for("webhooks"), json.dumps(body)) - return json_to_py(response) - - def test_webhook(self, webhook_id): - """Tests that a post can be made to the endpoint specified for the webhook - identified by webhook_id.""" - response = self._get(self.uri_for("webhooks/%s/test" % webhook_id)) - return True # An exception will be raised if any error occurs - - def delete_webhook(self, webhook_id): - """Deletes a webhook associated with this list.""" - response = self._delete("/lists/%s/webhooks/%s.json" % (self.list_id, webhook_id)) - - def activate_webhook(self, webhook_id): - """Activates a webhook associated with this list.""" - response = self._put(self.uri_for("webhooks/%s/activate" % webhook_id), ' ') - - def deactivate_webhook(self, webhook_id): - """De-activates a webhook associated with this list.""" - response = self._put(self.uri_for("webhooks/%s/deactivate" % webhook_id), ' ') - - def uri_for(self, action): - return "/lists/%s/%s.json" % (self.list_id, action) + """Represents a subscriber list and associated functionality.""" + + def __init__(self, auth=None, list_id=None): + self.list_id = list_id + super(List, self).__init__(auth) + + def create(self, client_id, title, unsubscribe_page, confirmed_opt_in, + confirmation_success_page, unsubscribe_setting="AllClientLists"): + """Creates a new list for a client.""" + body = { + "Title": title, + "UnsubscribePage": unsubscribe_page, + "ConfirmedOptIn": confirmed_opt_in, + "ConfirmationSuccessPage": confirmation_success_page, + "UnsubscribeSetting": unsubscribe_setting} + response = self._post("/lists/%s.json" % client_id, json.dumps(body)) + self.list_id = json_to_py(response) + return self.list_id + + def delete(self): + """Deletes this list.""" + response = self._delete("/lists/%s.json" % self.list_id) + + def create_custom_field(self, field_name, data_type, options=[], + visible_in_preference_center=True): + """Creates a new custom field for this list.""" + body = { + "FieldName": field_name, + "DataType": data_type, + "Options": options, + "VisibleInPreferenceCenter": visible_in_preference_center} + response = self._post(self.uri_for("customfields"), json.dumps(body)) + return json_to_py(response) + + def update_custom_field(self, custom_field_key, field_name, + visible_in_preference_center): + """Updates a custom field belonging to this list.""" + custom_field_key = quote(custom_field_key, '') + body = { + "FieldName": field_name, + "VisibleInPreferenceCenter": visible_in_preference_center} + response = self._put(self.uri_for("customfields/%s" % + custom_field_key), json.dumps(body)) + return json_to_py(response) + + def delete_custom_field(self, custom_field_key): + """Deletes a custom field associated with this list.""" + custom_field_key = quote(custom_field_key, '') + response = self._delete("/lists/%s/customfields/%s.json" % + (self.list_id, custom_field_key)) + + def update_custom_field_options(self, custom_field_key, new_options, + keep_existing_options): + """Updates the options of a multi-optioned custom field on this list.""" + custom_field_key = quote(custom_field_key, '') + body = { + "Options": new_options, + "KeepExistingOptions": keep_existing_options} + response = self._put(self.uri_for( + "customfields/%s/options" % custom_field_key), json.dumps(body)) + + def details(self): + """Gets the details of this list.""" + response = self._get("/lists/%s.json" % self.list_id) + return json_to_py(response) + + def custom_fields(self): + """Gets the custom fields for this list.""" + response = self._get(self.uri_for("customfields")) + return json_to_py(response) + + def segments(self): + """Gets the segments for this list.""" + response = self._get(self.uri_for("segments")) + return json_to_py(response) + + def stats(self): + """Gets the stats for this list.""" + response = self._get(self.uri_for("stats")) + return json_to_py(response) + + def active(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): + """Gets the active subscribers for this list.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("active"), params=params) + return json_to_py(response) + + def unconfirmed(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): + """Gets the unconfirmed subscribers for this list.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("unconfirmed"), params=params) + return json_to_py(response) + + def bounced(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): + """Gets the bounced subscribers for this list.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("bounced"), params=params) + return json_to_py(response) + + def unsubscribed(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): + """Gets the unsubscribed subscribers for this list.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("unsubscribed"), params=params) + return json_to_py(response) + + def deleted(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): + """Gets the deleted subscribers for this list.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("deleted"), params=params) + return json_to_py(response) + + def update(self, title, unsubscribe_page, confirmed_opt_in, + confirmation_success_page, unsubscribe_setting="AllClientLists", + add_unsubscribes_to_supp_list=False, scrub_active_with_supp_list=False): + """Updates this list.""" + body = { + "Title": title, + "UnsubscribePage": unsubscribe_page, + "ConfirmedOptIn": confirmed_opt_in, + "ConfirmationSuccessPage": confirmation_success_page, + "UnsubscribeSetting": unsubscribe_setting, + "AddUnsubscribesToSuppList": add_unsubscribes_to_supp_list, + "ScrubActiveWithSuppList": scrub_active_with_supp_list} + response = self._put("/lists/%s.json" % self.list_id, json.dumps(body)) + + def webhooks(self): + """Gets the webhooks for this list.""" + response = self._get(self.uri_for("webhooks")) + return json_to_py(response) + + def create_webhook(self, events, url, payload_format): + """Creates a new webhook for the specified events (an array of strings). + Valid events are "Subscribe", "Deactivate", and "Update". + Valid payload formats are "json", and "xml".""" + body = { + "Events": events, + "Url": url, + "PayloadFormat": payload_format} + response = self._post(self.uri_for("webhooks"), json.dumps(body)) + return json_to_py(response) + + def test_webhook(self, webhook_id): + """Tests that a post can be made to the endpoint specified for the webhook + identified by webhook_id.""" + response = self._get(self.uri_for("webhooks/%s/test" % webhook_id)) + return True # An exception will be raised if any error occurs + + def delete_webhook(self, webhook_id): + """Deletes a webhook associated with this list.""" + response = self._delete("/lists/%s/webhooks/%s.json" % + (self.list_id, webhook_id)) + + def activate_webhook(self, webhook_id): + """Activates a webhook associated with this list.""" + response = self._put(self.uri_for( + "webhooks/%s/activate" % webhook_id), ' ') + + def deactivate_webhook(self, webhook_id): + """De-activates a webhook associated with this list.""" + response = self._put(self.uri_for( + "webhooks/%s/deactivate" % webhook_id), ' ') + + def uri_for(self, action): + return "/lists/%s/%s.json" % (self.list_id, action) diff --git a/createsend/person.py b/createsend/person.py index 3d2aa43..98cc560 100644 --- a/createsend/person.py +++ b/createsend/person.py @@ -1,48 +1,53 @@ try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase, BadRequest -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase +from createsend.utils import json_to_py + class Person(CreateSendBase): - """Represents a person and associated functionality.""" + """Represents a person and associated functionality.""" - def __init__(self, auth=None, client_id=None, email_address=None): - self.client_id = client_id - self.email_address = email_address - super(Person, self).__init__(auth) + def __init__(self, auth=None, client_id=None, email_address=None): + self.client_id = client_id + self.email_address = email_address + super(Person, self).__init__(auth) - def get(self, client_id=None, email_address=None): - """Gets a person by client ID and email address.""" - params = { "email": email_address or self.email_address } - response = self._get("/clients/%s/people.json" % (client_id or self.client_id), params=params) - return json_to_py(response) + def get(self, client_id=None, email_address=None): + """Gets a person by client ID and email address.""" + params = {"email": email_address or self.email_address} + response = self._get("/clients/%s/people.json" % + (client_id or self.client_id), params=params) + return json_to_py(response) - def add(self, client_id, email_address, name, access_level, password): - """Adds a person to a client. Password is optional and if not supplied, an invitation will be emailed to the person""" - body = { - "EmailAddress": email_address, - "Name": name, - "AccessLevel": access_level, - "Password": password} - response = self._post("/clients/%s/people.json" % client_id, json.dumps(body)) - return json_to_py(response) + def add(self, client_id, email_address, name, access_level, password): + """Adds a person to a client. Password is optional and if not supplied, an invitation will be emailed to the person""" + body = { + "EmailAddress": email_address, + "Name": name, + "AccessLevel": access_level, + "Password": password} + response = self._post("/clients/%s/people.json" % + client_id, json.dumps(body)) + return json_to_py(response) - def update(self, new_email_address, name, access_level, password = None): - """Updates the details for a person. Password is optional and is only updated if supplied.""" - params = { "email": self.email_address } - body = { - "EmailAddress": new_email_address, - "Name": name, - "AccessLevel": access_level, - "Password": password} - response = self._put("/clients/%s/people.json" % self.client_id, - body=json.dumps(body), params=params) - # Update self.email_address, so this object can continue to be used reliably - self.email_address = new_email_address + def update(self, new_email_address, name, access_level, password=None): + """Updates the details for a person. Password is optional and is only updated if supplied.""" + params = {"email": self.email_address} + body = { + "EmailAddress": new_email_address, + "Name": name, + "AccessLevel": access_level, + "Password": password} + response = self._put("/clients/%s/people.json" % self.client_id, + body=json.dumps(body), params=params) + # Update self.email_address, so this object can continue to be used + # reliably + self.email_address = new_email_address - def delete(self): - """Deletes the person from the client.""" - params = { "email": self.email_address } - response = self._delete("/clients/%s/people.json" % self.client_id, params=params) + def delete(self): + """Deletes the person from the client.""" + params = {"email": self.email_address} + response = self._delete("/clients/%s/people.json" % + self.client_id, params=params) diff --git a/createsend/segment.py b/createsend/segment.py index 236e1f7..6620746 100644 --- a/createsend/segment.py +++ b/createsend/segment.py @@ -1,61 +1,64 @@ try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase +from createsend.utils import json_to_py + class Segment(CreateSendBase): - """Represents a subscriber list segment and associated functionality.""" - - def __init__(self, auth=None, segment_id=None): - self.segment_id = segment_id - super(Segment, self).__init__(auth) - - def create(self, list_id, title, rulegroups): - """Creates a new segment.""" - body = { - "Title": title, - "RuleGroups": rulegroups } - response = self._post("/segments/%s.json" % list_id, json.dumps(body)) - self.segment_id = json_to_py(response) - return self.segment_id - - def update(self, title, rulegroups): - """Updates this segment.""" - body = { - "Title": title, - "RuleGroups": rulegroups } - response = self._put("/segments/%s.json" % self.segment_id, json.dumps(body)) - - def add_rulegroup(self, rulegroup): - """Adds a rulegroup to this segment.""" - body = rulegroup - response = self._post("/segments/%s/rules.json" % self.segment_id, json.dumps(body)) - - def subscribers(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): - """Gets the active subscribers in this segment.""" - params = { - "date": date, - "page": page, - "pagesize": page_size, - "orderfield": order_field, - "orderdirection": order_direction } - response = self._get(self.uri_for("active"), params=params) - return json_to_py(response) - - def details(self): - """Gets the details of this segment""" - response = self._get("/segments/%s.json" % self.segment_id) - return json_to_py(response) - - def clear_rules(self): - """Clears all rules of this segment.""" - response = self._delete("/segments/%s/rules.json" % self.segment_id) - - def delete(self): - """Deletes this segment.""" - response = self._delete("/segments/%s.json" % self.segment_id) - - def uri_for(self, action): - return "/segments/%s/%s.json" % (self.segment_id, action) + """Represents a subscriber list segment and associated functionality.""" + + def __init__(self, auth=None, segment_id=None): + self.segment_id = segment_id + super(Segment, self).__init__(auth) + + def create(self, list_id, title, rulegroups): + """Creates a new segment.""" + body = { + "Title": title, + "RuleGroups": rulegroups} + response = self._post("/segments/%s.json" % list_id, json.dumps(body)) + self.segment_id = json_to_py(response) + return self.segment_id + + def update(self, title, rulegroups): + """Updates this segment.""" + body = { + "Title": title, + "RuleGroups": rulegroups} + response = self._put("/segments/%s.json" % + self.segment_id, json.dumps(body)) + + def add_rulegroup(self, rulegroup): + """Adds a rulegroup to this segment.""" + body = rulegroup + response = self._post("/segments/%s/rules.json" % + self.segment_id, json.dumps(body)) + + def subscribers(self, date="", page=1, page_size=1000, order_field="email", order_direction="asc"): + """Gets the active subscribers in this segment.""" + params = { + "date": date, + "page": page, + "pagesize": page_size, + "orderfield": order_field, + "orderdirection": order_direction} + response = self._get(self.uri_for("active"), params=params) + return json_to_py(response) + + def details(self): + """Gets the details of this segment""" + response = self._get("/segments/%s.json" % self.segment_id) + return json_to_py(response) + + def clear_rules(self): + """Clears all rules of this segment.""" + response = self._delete("/segments/%s/rules.json" % self.segment_id) + + def delete(self): + """Deletes this segment.""" + response = self._delete("/segments/%s.json" % self.segment_id) + + def uri_for(self, action): + return "/segments/%s/%s.json" % (self.segment_id, action) diff --git a/createsend/subscriber.py b/createsend/subscriber.py index bc692dc..f793d01 100644 --- a/createsend/subscriber.py +++ b/createsend/subscriber.py @@ -1,83 +1,91 @@ try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase, BadRequest -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase, BadRequest +from createsend.utils import json_to_py + class Subscriber(CreateSendBase): - """Represents a subscriber and associated functionality.""" + """Represents a subscriber and associated functionality.""" - def __init__(self, auth=None, list_id=None, email_address=None): - self.list_id = list_id - self.email_address = email_address - super(Subscriber, self).__init__(auth) + def __init__(self, auth=None, list_id=None, email_address=None): + self.list_id = list_id + self.email_address = email_address + super(Subscriber, self).__init__(auth) - def get(self, list_id=None, email_address=None): - """Gets a subscriber by list ID and email address.""" - params = { "email": email_address or self.email_address } - response = self._get("/subscribers/%s.json" % (list_id or self.list_id), params=params) - return json_to_py(response) + def get(self, list_id=None, email_address=None): + """Gets a subscriber by list ID and email address.""" + params = {"email": email_address or self.email_address} + response = self._get("/subscribers/%s.json" % + (list_id or self.list_id), params=params) + return json_to_py(response) - def add(self, list_id, email_address, name, custom_fields, resubscribe, restart_subscription_based_autoresponders=False): - """Adds a subscriber to a subscriber list.""" - body = { - "EmailAddress": email_address, - "Name": name, - "CustomFields": custom_fields, - "Resubscribe": resubscribe, - "RestartSubscriptionBasedAutoresponders": restart_subscription_based_autoresponders } - response = self._post("/subscribers/%s.json" % list_id, json.dumps(body)) - return json_to_py(response) + def add(self, list_id, email_address, name, custom_fields, resubscribe, restart_subscription_based_autoresponders=False): + """Adds a subscriber to a subscriber list.""" + body = { + "EmailAddress": email_address, + "Name": name, + "CustomFields": custom_fields, + "Resubscribe": resubscribe, + "RestartSubscriptionBasedAutoresponders": restart_subscription_based_autoresponders} + response = self._post("/subscribers/%s.json" % + list_id, json.dumps(body)) + return json_to_py(response) - def update(self, new_email_address, name, custom_fields, resubscribe, restart_subscription_based_autoresponders=False): - """Updates any aspect of a subscriber, including email address, name, and - custom field data if supplied.""" - params = { "email": self.email_address } - body = { - "EmailAddress": new_email_address, - "Name": name, - "CustomFields": custom_fields, - "Resubscribe": resubscribe, - "RestartSubscriptionBasedAutoresponders": restart_subscription_based_autoresponders } - response = self._put("/subscribers/%s.json" % self.list_id, - body=json.dumps(body), params=params) - # Update self.email_address, so this object can continue to be used reliably - self.email_address = new_email_address + def update(self, new_email_address, name, custom_fields, resubscribe, restart_subscription_based_autoresponders=False): + """Updates any aspect of a subscriber, including email address, name, and + custom field data if supplied.""" + params = {"email": self.email_address} + body = { + "EmailAddress": new_email_address, + "Name": name, + "CustomFields": custom_fields, + "Resubscribe": resubscribe, + "RestartSubscriptionBasedAutoresponders": restart_subscription_based_autoresponders} + response = self._put("/subscribers/%s.json" % self.list_id, + body=json.dumps(body), params=params) + # Update self.email_address, so this object can continue to be used + # reliably + self.email_address = new_email_address - def import_subscribers(self, list_id, subscribers, resubscribe, queue_subscription_based_autoresponders=False, restart_subscription_based_autoresponders=False): - """Imports subscribers into a subscriber list.""" - body = { - "Subscribers": subscribers, - "Resubscribe": resubscribe, - "QueueSubscriptionBasedAutoresponders": queue_subscription_based_autoresponders, - "RestartSubscriptionBasedAutoresponders": restart_subscription_based_autoresponders } - try: - response = self._post("/subscribers/%s/import.json" % list_id, json.dumps(body)) - except BadRequest as br: - # Subscriber import will throw BadRequest if some subscribers are not imported - # successfully. If this occurs, we want to return the ResultData property of - # the BadRequest exception (which is of the same "form" as the response we'd - # receive upon a completely successful import) - if hasattr(br.data, 'ResultData'): - return br.data.ResultData - else: - raise br - return json_to_py(response) + def import_subscribers(self, list_id, subscribers, resubscribe, queue_subscription_based_autoresponders=False, restart_subscription_based_autoresponders=False): + """Imports subscribers into a subscriber list.""" + body = { + "Subscribers": subscribers, + "Resubscribe": resubscribe, + "QueueSubscriptionBasedAutoresponders": queue_subscription_based_autoresponders, + "RestartSubscriptionBasedAutoresponders": restart_subscription_based_autoresponders} + try: + response = self._post("/subscribers/%s/import.json" % + list_id, json.dumps(body)) + except BadRequest as br: + # Subscriber import will throw BadRequest if some subscribers are not imported + # successfully. If this occurs, we want to return the ResultData property of + # the BadRequest exception (which is of the same "form" as the response we'd + # receive upon a completely successful import) + if hasattr(br.data, 'ResultData'): + return br.data.ResultData + else: + raise br + return json_to_py(response) - def unsubscribe(self): - """Unsubscribes this subscriber from the associated list.""" - body = { - "EmailAddress": self.email_address } - response = self._post("/subscribers/%s/unsubscribe.json" % self.list_id, json.dumps(body)) + def unsubscribe(self): + """Unsubscribes this subscriber from the associated list.""" + body = { + "EmailAddress": self.email_address} + response = self._post("/subscribers/%s/unsubscribe.json" % + self.list_id, json.dumps(body)) - def history(self): - """Gets the historical record of this subscriber's trackable actions.""" - params = { "email": self.email_address } - response = self._get("/subscribers/%s/history.json" % self.list_id, params=params) - return json_to_py(response) + def history(self): + """Gets the historical record of this subscriber's trackable actions.""" + params = {"email": self.email_address} + response = self._get("/subscribers/%s/history.json" % + self.list_id, params=params) + return json_to_py(response) - def delete(self): - """Moves this subscriber to the deleted state in the associated list.""" - params = { "email": self.email_address } - response = self._delete("/subscribers/%s.json" % self.list_id, params=params) + def delete(self): + """Moves this subscriber to the deleted state in the associated list.""" + params = {"email": self.email_address} + response = self._delete("/subscribers/%s.json" % + self.list_id, params=params) diff --git a/createsend/template.py b/createsend/template.py index d18c53a..f78ceec 100644 --- a/createsend/template.py +++ b/createsend/template.py @@ -1,40 +1,43 @@ try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase +from createsend.utils import json_to_py + class Template(CreateSendBase): - """Represents an email template and associated functionality.""" + """Represents an email template and associated functionality.""" - def __init__(self, auth=None, template_id=None): - self.template_id = template_id - super(Template, self).__init__(auth) + def __init__(self, auth=None, template_id=None): + self.template_id = template_id + super(Template, self).__init__(auth) - def create(self, client_id, name, html_url, zip_url): - """Creates a new email template.""" - body = { - "Name": name, - "HtmlPageURL": html_url, - "ZipFileURL": zip_url } - response = self._post("/templates/%s.json" % client_id, json.dumps(body)) - self.template_id = json_to_py(response) - return self.template_id + def create(self, client_id, name, html_url, zip_url): + """Creates a new email template.""" + body = { + "Name": name, + "HtmlPageURL": html_url, + "ZipFileURL": zip_url} + response = self._post("/templates/%s.json" % + client_id, json.dumps(body)) + self.template_id = json_to_py(response) + return self.template_id - def details(self): - """Gets the details of this email template.""" - response = self._get("/templates/%s.json" % self.template_id) - return json_to_py(response) + def details(self): + """Gets the details of this email template.""" + response = self._get("/templates/%s.json" % self.template_id) + return json_to_py(response) - def update(self, name, html_url, zip_url): - """Updates this email template.""" - body = { - "Name": name, - "HtmlPageURL": html_url, - "ZipFileURL": zip_url } - response = self._put("/templates/%s.json" % self.template_id, json.dumps(body)) + def update(self, name, html_url, zip_url): + """Updates this email template.""" + body = { + "Name": name, + "HtmlPageURL": html_url, + "ZipFileURL": zip_url} + response = self._put("/templates/%s.json" % + self.template_id, json.dumps(body)) - def delete(self): - """Deletes this email template.""" - response = self._delete("/templates/%s.json" % self.template_id) + def delete(self): + """Deletes this email template.""" + response = self._delete("/templates/%s.json" % self.template_id) diff --git a/createsend/transactional.py b/createsend/transactional.py index 52e05ec..2f92708 100644 --- a/createsend/transactional.py +++ b/createsend/transactional.py @@ -1,88 +1,96 @@ try: - import json + import json except ImportError: - import simplejson as json -from .createsend import CreateSendBase -from .utils import json_to_py + import simplejson as json +from createsend.createsend import CreateSendBase +from createsend.utils import json_to_py + class Transactional(CreateSendBase): - """Represents transactional functionality.""" + """Represents transactional functionality.""" - def __init__(self, auth=None, client_id=None): - self.client_id = client_id - super(Transactional, self).__init__(auth) + def __init__(self, auth=None, client_id=None): + self.client_id = client_id + super(Transactional, self).__init__(auth) - def smart_email_list(self, status="all", client_id=None): - """Gets the smart email list.""" - if client_id is None: - response = self._get("/transactional/smartEmail?status=%s" % status) - else: - response = self._get("/transactional/smartEmail?status=%s&clientID=%s" % (status, client_id)) - return json_to_py(response) + def smart_email_list(self, status="all", client_id=None): + """Gets the smart email list.""" + if client_id is None: + response = self._get( + "/transactional/smartEmail?status=%s" % status) + else: + response = self._get( + "/transactional/smartEmail?status=%s&clientID=%s" % (status, client_id)) + return json_to_py(response) - def smart_email_details(self, smart_email_id): - """Gets the smart email details.""" - response = self._get("/transactional/smartEmail/%s" % smart_email_id) - return json_to_py(response) + def smart_email_details(self, smart_email_id): + """Gets the smart email details.""" + response = self._get("/transactional/smartEmail/%s" % smart_email_id) + return json_to_py(response) - def smart_email_send(self, smart_email_id, to, cc=None, bcc=None, attachments=None, data=None, add_recipients_to_list=None): - """Sends the smart email.""" - body = { - "To": to, - "CC": cc, - "BCC": bcc, - "Attachments": attachments, - "Data": data, - "AddRecipientsToList": add_recipients_to_list } - response = self._post("/transactional/smartEmail/%s/send" % smart_email_id, json.dumps(body)) - return json_to_py(response) + def smart_email_send(self, smart_email_id, to, cc=None, bcc=None, attachments=None, data=None, add_recipients_to_list=None): + """Sends the smart email.""" + body = { + "To": to, + "CC": cc, + "BCC": bcc, + "Attachments": attachments, + "Data": data, + "AddRecipientsToList": add_recipients_to_list} + response = self._post("/transactional/smartEmail/%s/send" % + smart_email_id, json.dumps(body)) + return json_to_py(response) - def classic_email_send(self, subject, from_address, to, client_id=None, cc=None, bcc=None, html=None, text=None, attachments=None, track_opens=True, track_clicks=True, inline_css=True, group=None, add_recipients_to_list=None): - """Sends a classic email.""" - body = { - "Subject": subject, - "From": from_address, - "To": to, - "CC": cc, - "BCC": bcc, - "HTML": html, - "Text": text, - "Attachments": attachments, - "TrackOpens": track_opens, - "TrackClicks": track_clicks, - "InlineCSS": inline_css, - "Group": group, - "AddRecipientsToList": add_recipients_to_list } - if client_id is None: - response = self._post("/transactional/classicEmail/send", json.dumps(body)) - else: - response = self._post("/transactional/classicEmail/send?clientID=%s" % client_id, json.dumps(body)) - return json_to_py(response) + def classic_email_send(self, subject, from_address, to, client_id=None, cc=None, bcc=None, html=None, text=None, attachments=None, track_opens=True, track_clicks=True, inline_css=True, group=None, add_recipients_to_list=None): + """Sends a classic email.""" + body = { + "Subject": subject, + "From": from_address, + "To": to, + "CC": cc, + "BCC": bcc, + "HTML": html, + "Text": text, + "Attachments": attachments, + "TrackOpens": track_opens, + "TrackClicks": track_clicks, + "InlineCSS": inline_css, + "Group": group, + "AddRecipientsToList": add_recipients_to_list} + if client_id is None: + response = self._post( + "/transactional/classicEmail/send", json.dumps(body)) + else: + response = self._post( + "/transactional/classicEmail/send?clientID=%s" % client_id, json.dumps(body)) + return json_to_py(response) - def classic_email_groups(self, client_id=None): - """Gets the list of classic email groups.""" - if client_id is None: - response = self._get("/transactional/classicEmail/groups") - else: - response = self._get("/transactional/classicEmail/groups?clientID=%s" % client_id) - return json_to_py(response) + def classic_email_groups(self, client_id=None): + """Gets the list of classic email groups.""" + if client_id is None: + response = self._get("/transactional/classicEmail/groups") + else: + response = self._get( + "/transactional/classicEmail/groups?clientID=%s" % client_id) + return json_to_py(response) - def statistics(self, params={}): - """Gets the statistics according to the parameters.""" - response = self._get("/transactional/statistics", params) - return json_to_py(response) + def statistics(self, params={}): + """Gets the statistics according to the parameters.""" + response = self._get("/transactional/statistics", params) + return json_to_py(response) - def message_timeline(self, params={}): - """Gets the messages timeline according to the parameters.""" - response = self._get("/transactional/messages", params) - return json_to_py(response) + def message_timeline(self, params={}): + """Gets the messages timeline according to the parameters.""" + response = self._get("/transactional/messages", params) + return json_to_py(response) - def message_details(self, message_id, statistics=False): - """Gets the details of this message.""" - response = self._get("/transactional/messages/%s?statistics=%s" % (message_id, statistics)) - return json_to_py(response) + def message_details(self, message_id, statistics=False): + """Gets the details of this message.""" + response = self._get( + "/transactional/messages/%s?statistics=%s" % (message_id, statistics)) + return json_to_py(response) - def message_resend(self, message_id): - """Resend the message.""" - response = self._post("/transactional/messages/%s/resend" % message_id) - return json_to_py(response) + def message_resend(self, message_id): + """Resend the message.""" + response = self._post("/transactional/messages/%s/resend" % message_id) + return json_to_py(response) diff --git a/createsend/utils.py b/createsend/utils.py index 11a6690..76de74b 100644 --- a/createsend/utils.py +++ b/createsend/utils.py @@ -4,150 +4,161 @@ import socket import ssl try: - import json + import json except ImportError: - import simplejson as json + import simplejson as json + class CertificateError(ValueError): - """ - Raised when an error occurs when attempting to verify an SSL certificate. - """ - pass + """ + Raised when an error occurs when attempting to verify an SSL certificate. + """ + pass + def _dnsname_to_pat(dn): - pats = [] - for frag in dn.split(r'.'): - if frag == '*': - # When '*' is a fragment by itself, it matches a non-empty dotless - # fragment. - pats.append('[^.]+') - else: - # Otherwise, '*' matches any dotless fragment. - frag = re.escape(frag) - pats.append(frag.replace(r'\*', '[^.]*')) - return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + pats = [] + for frag in dn.split(r'.'): + if frag == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + else: + # Otherwise, '*' matches any dotless fragment. + frag = re.escape(frag) + pats.append(frag.replace(r'\*', '[^.]*')) + return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + def match_hostname(cert, hostname): - """ - This is a backport of the match_hostname() function from Python 3.2, - essential when using SSL. - Verifies that *cert* (in decoded format as returned by - SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules - are mostly followed, but IP addresses are not accepted for *hostname*. - - CertificateError is raised on failure. On success, the function - returns nothing. - """ - if not cert: - raise ValueError("empty or no certificate") - dnsnames = [] - san = cert.get('subjectAltName', ()) - for key, value in san: - if key == 'DNS': - if _dnsname_to_pat(value).match(hostname): - return - dnsnames.append(value) - if not san: - # The subject is only checked when subjectAltName is empty - for sub in cert.get('subject', ()): - for key, value in sub: - # XXX according to RFC 2818, the most specific Common Name - # must be used. - if key == 'commonName': - if _dnsname_to_pat(value).match(hostname): - return - dnsnames.append(value) - if len(dnsnames) > 1: - raise CertificateError("hostname %r " - "doesn't match either of %s" - % (hostname, ', '.join(map(repr, dnsnames)))) - elif len(dnsnames) == 1: - raise CertificateError("hostname %r " - "doesn't match %r" - % (hostname, dnsnames[0])) - else: - raise CertificateError("no appropriate commonName or " - "subjectAltName fields were found") + """ + This is a backport of the match_hostname() function from Python 3.2, + essential when using SSL. + Verifies that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules + are mostly followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError("empty or no certificate") + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if _dnsname_to_pat(value).match(hostname): + return + dnsnames.append(value) + if not san: + # The subject is only checked when subjectAltName is empty + for sub in cert.get('subject', ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == 'commonName': + if _dnsname_to_pat(value).match(hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError("hostname %r " + "doesn't match either of %s" + % (hostname, ', '.join(map(repr, dnsnames)))) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r " + "doesn't match %r" + % (hostname, dnsnames[0])) + else: + raise CertificateError("no appropriate commonName or " + "subjectAltName fields were found") + class VerifiedHTTPSConnection(HTTPSConnection): - """ - A connection that includes SSL certificate verification. - """ - def connect(self): - self.connection_kwargs = {} - # for > py2.5 - if hasattr(self, 'timeout'): - self.connection_kwargs.update(timeout = self.timeout) - - # for >= py2.7 - if hasattr(self, 'source_address'): - self.connection_kwargs.update(source_address = self.source_address) - - sock = socket.create_connection((self.host, self.port), **self.connection_kwargs) - - # for >= py2.7 - if getattr(self, '_tunnel_host', None): - self.sock = sock - self._tunnel() - - cert_path = os.path.join(os.path.dirname(__file__), 'cacert.pem') - - self.sock = ssl.wrap_socket( - sock, - self.key_file, - self.cert_file, - cert_reqs=ssl.CERT_REQUIRED, - ca_certs=cert_path) - - try: - match_hostname(self.sock.getpeercert(), self.host) - except CertificateError: - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() - raise + """ + A connection that includes SSL certificate verification. + """ + + def connect(self): + self.connection_kwargs = {} + # for > py2.5 + if hasattr(self, 'timeout'): + self.connection_kwargs.update(timeout=self.timeout) + + # for >= py2.7 + if hasattr(self, 'source_address'): + self.connection_kwargs.update(source_address=self.source_address) + + sock = socket.create_connection( + (self.host, self.port), **self.connection_kwargs) + + # for >= py2.7 + if getattr(self, '_tunnel_host', None): + self.sock = sock + self._tunnel() + + cert_path = os.path.join(os.path.dirname(__file__), 'cacert.pem') + + self.sock = ssl.wrap_socket( + sock, + self.key_file, + self.cert_file, + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=cert_path) + + try: + match_hostname(self.sock.getpeercert(), self.host) + except CertificateError: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + raise + def json_to_py(j): - o = json.loads(j.decode('utf-8')) - if isinstance(o, dict): - return dict_to_object(o) - else: - return dict_to_object({ "response": o }).response + o = json.loads(j.decode('utf-8')) + if isinstance(o, dict): + return dict_to_object(o) + else: + return dict_to_object({"response": o}).response + def dict_to_object(d): - """Recursively converts a dict to an object""" - top = type('CreateSendModel', (object,), d) - seqs = tuple, list, set, frozenset - for i, j in d.items(): - if isinstance(j, dict): - setattr(top, i, dict_to_object(j)) - elif isinstance(j, seqs): - setattr(top, i, type(j)(dict_to_object(sj) if isinstance(sj, dict) else sj for sj in j)) - else: - setattr(top, i, j) - return top - -def get_faker(expected_url, filename, status=None, body = None): - - class Faker(object): - """Represents a fake web request, including the expected URL, an open - function which reads the expected response from a fixture file, and the - expected response status code.""" - def __init__(self, expected_url, filename, status, body = None): - self.url = self.createsend_url(expected_url) - self.filename = filename - self.status = status - self.body = body - - def open(self): - if self.filename: - return open("%s/../test/fixtures/%s" % (os.path.dirname(__file__), self.filename), mode='rb').read() - else: - return '' - - def createsend_url(self, url): - if url.startswith("http"): - return url - else: - return "https://api.createsend.com/api/v3.1/%s" % url - - return Faker(expected_url, filename, status, body) + """Recursively converts a dict to an object""" + top = type('CreateSendModel', (object,), d) + seqs = tuple, list, set, frozenset + for i, j in list(d.items()): + if isinstance(j, dict): + setattr(top, i, dict_to_object(j)) + elif isinstance(j, seqs): + setattr(top, i, type(j)(dict_to_object(sj) + if isinstance(sj, dict) else sj for sj in j)) + else: + setattr(top, i, j) + return top + + +def get_faker(expected_url, filename, status=None, body=None): + + class Faker(object): + """Represents a fake web request, including the expected URL, an open + function which reads the expected response from a fixture file, and the + expected response status code.""" + + def __init__(self, expected_url, filename, status, body=None): + self.url = self.createsend_url(expected_url) + self.filename = filename + self.status = status + self.body = body + + def open(self): + if self.filename: + return open("%s/../test/fixtures/%s" % (os.path.dirname(__file__), self.filename), mode='rb').read() + else: + return '' + + def createsend_url(self, url): + if url.startswith("http"): + return url + else: + return "https://api.createsend.com/api/v3.1/%s" % url + + return Faker(expected_url, filename, status, body) diff --git a/createsend/version.py b/createsend/version.py new file mode 100644 index 0000000..6a6dbe9 --- /dev/null +++ b/createsend/version.py @@ -0,0 +1,10 @@ +""" +To change the version of entire package, just edit this one location. +""" +__title__ = 'createsend-python' +__author__ = 'Dylan Stein' +__license__ = 'MIT' +__copyright__ = 'Copyright 2017' + +version_info = (4, 2, 1) +__version__ = ".".join(map(str, version_info)) diff --git a/nosetests.py b/nosetests.py index e3e7e5e..c5abf62 100644 --- a/nosetests.py +++ b/nosetests.py @@ -1,4 +1,3 @@ import nose nose.run() - diff --git a/requirements.txt b/requirements.txt index b6e2ad5..df66c8c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -nose==1.2.1 -coverage -coveralls -six +six==1.10.0 +nose==1.3.7 +coverage==4.4.1 +coveralls==1.1 diff --git a/setup.py b/setup.py index 147b6f2..7709e7c 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,17 @@ -import sys -import os from distutils.core import setup from createsend.createsend import __version__ -setup(name = "createsend", - version = __version__, - description = "A library which implements the complete functionality of the Campaign Monitor API.", - author = "James Dennes", - author_email = 'jdennes@gmail.com', - url = "http://campaignmonitor.github.io/createsend-python/", - license = "MIT", - keywords = "createsend campaign monitor email", - packages = ['createsend'], - package_data = {'createsend': ['cacert.pem']}) +setup( + name="createsend", + version=__version__, + description="A library which implements the complete functionality of the Campaign Monitor API.", + author="Dylan Stein", + author_email='djstein@ncsu.edu', + url="http://campaignmonitor.github.io/createsend-python/", + license="MIT", + keywords="createsend campaign monitor email", + packages=['createsend'], + package_data={'createsend': ['cacert.pem']}, + install_requires=['six'], +) diff --git a/test/test_administrator.py b/test/test_administrator.py index 9988a21..5aa7a9a 100644 --- a/test/test_administrator.py +++ b/test/test_administrator.py @@ -1,49 +1,58 @@ from six.moves.urllib.parse import quote import unittest -from createsend import * +from createsend.administrator import Administrator + class AdministratorTestCase(object): - def test_get(self): - email = "admin@example.com" - self.administrator.stub_request("admins.json?email=%s" % quote(email), "admin_details.json") - administrator = self.administrator.get(email) - self.assertEquals(administrator.EmailAddress, email) - self.assertEquals(administrator.Name, "Admin One") - self.assertEquals(administrator.Status, "Active") - - def test_get_without_args(self): - email = "admin@example.com" - self.administrator.stub_request("admins.json?email=%s" % quote(email), "admin_details.json") - administrator = self.administrator.get() - self.assertEquals(administrator.EmailAddress, email) - self.assertEquals(administrator.Name, "Admin One") - self.assertEquals(administrator.Status, "Active") - - def test_add(self): - self.administrator.stub_request("admins.json", "add_admin.json") - result = self.administrator.add("admin@example.com", "Admin Name") - self.assertEquals(result.EmailAddress, "admin@example.com") - - def test_update(self): - new_email = "new_email_address@example.com" - self.administrator.stub_request("admins.json?email=%s" % quote(self.administrator.email_address), None) - self.administrator.update(new_email, "Admin New Name") - self.assertEquals(self.administrator.email_address, new_email) - - def test_delete(self): - self.administrator.stub_request("admins.json?email=%s" % quote(self.administrator.email_address), None) - email_address = self.administrator.delete() + def test_get(self): + email = "admin@example.com" + self.administrator.stub_request( + "admins.json?email=%s" % quote(email), "admin_details.json") + administrator = self.administrator.get(email) + self.assertEquals(administrator.EmailAddress, email) + self.assertEquals(administrator.Name, "Admin One") + self.assertEquals(administrator.Status, "Active") + + def test_get_without_args(self): + email = "admin@example.com" + self.administrator.stub_request( + "admins.json?email=%s" % quote(email), "admin_details.json") + administrator = self.administrator.get() + self.assertEquals(administrator.EmailAddress, email) + self.assertEquals(administrator.Name, "Admin One") + self.assertEquals(administrator.Status, "Active") + + def test_add(self): + self.administrator.stub_request("admins.json", "add_admin.json") + result = self.administrator.add("admin@example.com", "Admin Name") + self.assertEquals(result.EmailAddress, "admin@example.com") + + def test_update(self): + new_email = "new_email_address@example.com" + self.administrator.stub_request("admins.json?email=%s" % quote( + self.administrator.email_address), None) + self.administrator.update(new_email, "Admin New Name") + self.assertEquals(self.administrator.email_address, new_email) + + def test_delete(self): + self.administrator.stub_request("admins.json?email=%s" % quote( + self.administrator.email_address), None) + email_address = self.administrator.delete() + class OAuthAdministatorTestCase(unittest.TestCase, AdministratorTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.administrator = Administrator( - {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, "admin@example.com") + """Test when using OAuth to authenticate""" + + def setUp(self): + self.administrator = Administrator( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, "admin@example.com") + class ApiKeyAdministatorTestCase(unittest.TestCase, AdministratorTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.administrator = Administrator( - {'api_key': '123123123123123123123'}, "admin@example.com") + """Test when using an API key to authenticate""" + + def setUp(self): + self.administrator = Administrator( + {'api_key': '123123123123123123123'}, "admin@example.com") diff --git a/test/test_authentication.py b/test/test_authentication.py index 76cbb04..468847a 100644 --- a/test/test_authentication.py +++ b/test/test_authentication.py @@ -1,113 +1,126 @@ -from six.moves.urllib.parse import urlparse +import base64 import unittest -from createsend import * +from createsend.createsend import CreateSend, ExpiredOAuthToken + class AuthenticationTestCase(unittest.TestCase): - def setUp(self): - self.oauth_auth_details = {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="} - self.api_key_auth_details = {'api_key': '123123123123123123123'} - - def test_authorize_url_with_state(self): - client_id = 8998879 - redirect_uri = 'http://example.com/auth' - scope = 'ViewReports,CreateCampaigns,SendCampaigns' - state = 89879287 - - self.cs = CreateSend(self.oauth_auth_details) - authorize_url = self.cs.authorize_url( - client_id=client_id, - redirect_uri=redirect_uri, - scope=scope, - state=state - ) - self.assertEquals(authorize_url, - "https://api.createsend.com/oauth?client_id=8998879&redirect_uri=http%3A%2F%2Fexample.com%2Fauth&scope=ViewReports%2CCreateCampaigns%2CSendCampaigns&state=89879287" - ) - - def test_authorize_url_without_state(self): - client_id = 8998879 - redirect_uri = 'http://example.com/auth' - scope = 'ViewReports,CreateCampaigns,SendCampaigns' - - self.cs = CreateSend(self.oauth_auth_details) - authorize_url = self.cs.authorize_url( - client_id=client_id, - redirect_uri=redirect_uri, - scope=scope - ) - self.assertEquals(authorize_url, - "https://api.createsend.com/oauth?client_id=8998879&redirect_uri=http%3A%2F%2Fexample.com%2Fauth&scope=ViewReports%2CCreateCampaigns%2CSendCampaigns" - ) - - def test_exchange_token_success(self): - client_id = 8998879 - client_secret = 'iou0q9wud0q9wd0q9wid0q9iwd0q9wid0q9wdqwd' - redirect_uri = 'http://example.com/auth' - code = '98uqw9d8qu9wdu' - self.cs = CreateSend(self.oauth_auth_details) - self.cs.stub_request("https://api.createsend.com/oauth/token", "oauth_exchange_token.json") - access_token, expires_in, refresh_token = self.cs.exchange_token( - client_id=client_id, - client_secret=client_secret, - redirect_uri=redirect_uri, - code=code - ) - self.assertEquals(self.cs.faker.actual_body, "grant_type=authorization_code&client_id=8998879&client_secret=iou0q9wud0q9wd0q9wid0q9iwd0q9wid0q9wdqwd&redirect_uri=http%3A%2F%2Fexample.com%2Fauth&code=98uqw9d8qu9wdu") - self.assertEquals(access_token, "SlAV32hkKG") - self.assertEquals(expires_in, 1209600) - self.assertEquals(refresh_token, "tGzv3JOkF0XG5Qx2TlKWIA") - - def test_echange_token_failure(self): - client_id = 8998879 - client_secret = 'iou0q9wud0q9wd0q9wid0q9iwd0q9wid0q9wdqwd' - redirect_uri = 'http://example.com/auth' - code = 'invalidcode' - self.cs = CreateSend(self.oauth_auth_details) - self.cs.stub_request("https://api.createsend.com/oauth/token", "oauth_exchange_token_error.json") - self.assertRaises(Exception, self.cs.exchange_token, client_id, client_secret, redirect_uri, code) - self.assertEquals(self.cs.faker.actual_body, "grant_type=authorization_code&client_id=8998879&client_secret=iou0q9wud0q9wd0q9wid0q9iwd0q9wid0q9wdqwd&redirect_uri=http%3A%2F%2Fexample.com%2Fauth&code=invalidcode") - - def test_can_authenticate_by_calling_auth_with_api_key(self): - self.cs = CreateSend(self.api_key_auth_details) - self.cs.stub_request("systemdate.json", "systemdate.json") - systemdate = self.cs.systemdate() - self.assertEquals(self.cs.headers['Authorization'], "Basic %s" % base64.b64encode(("%s:x" % self.api_key_auth_details['api_key']).encode()).decode()) - self.assertEquals(systemdate, "2010-10-15 09:27:00") - - def test_can_authenticate_by_calling_auth_with_oauth_credentials(self): - self.cs = CreateSend(self.oauth_auth_details) - self.cs.stub_request("systemdate.json", "systemdate.json") - systemdate = self.cs.systemdate() - self.assertEquals(self.cs.headers['Authorization'], "Bearer %s" % self.oauth_auth_details['access_token']) - self.assertEquals(systemdate, "2010-10-15 09:27:00") - - def test_raise_error_when_authenticating_with_oauth_and_token_expired(self): - self.cs = CreateSend(self.oauth_auth_details) - self.cs.stub_request("systemdate.json", 'expired_oauth_token_api_error.json', status=401) - self.assertRaises(ExpiredOAuthToken, self.cs.systemdate) - - def test_refresh_token(self): - self.cs = CreateSend(self.oauth_auth_details) - self.cs.stub_request("https://api.createsend.com/oauth/token", "refresh_oauth_token.json") - new_access_token, new_expires_in, new_refresh_token = self.cs.refresh_token() - - self.assertEquals(self.cs.faker.actual_body, "grant_type=refresh_token&refresh_token=5S4aASP9R%2B9KsgfHB0dapTYxNA%3D%3D") - self.assertEquals(new_access_token, "SlAV32hkKG2e12e") - self.assertEquals(new_expires_in, 1209600) - self.assertEquals(new_refresh_token, "tGzv3JOkF0XG5Qx2TlKWIA") - self.assertEquals(self.cs.auth_details, - { 'access_token': new_access_token, 'refresh_token': new_refresh_token }) - - def test_refresh_token_error_when_refresh_token_none(self): - self.cs = CreateSend({"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": None}) - self.assertRaises(Exception, self.cs.refresh_token) - - def test_refresh_token_error_when_no_refresh_token_passed_in(self): - self.cs = CreateSend({"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA=="}) - self.assertRaises(Exception, self.cs.refresh_token) - - def test_refresh_token_error_when_no_authentication(self): - self.cs = CreateSend() - self.assertRaises(Exception, self.cs.refresh_token) + def setUp(self): + self.oauth_auth_details = { + "access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="} + self.api_key_auth_details = {'api_key': '123123123123123123123'} + + def test_authorize_url_with_state(self): + client_id = 8998879 + redirect_uri = 'http://example.com/auth' + scope = 'ViewReports,CreateCampaigns,SendCampaigns' + state = 89879287 + + self.cs = CreateSend(self.oauth_auth_details) + authorize_url = self.cs.authorize_url( + client_id=client_id, + redirect_uri=redirect_uri, + scope=scope, + state=state + ) + self.assertEquals(authorize_url, + "https://api.createsend.com/oauth?client_id=8998879&redirect_uri=http%3A%2F%2Fexample.com%2Fauth&scope=ViewReports%2CCreateCampaigns%2CSendCampaigns&state=89879287" + ) + + def test_authorize_url_without_state(self): + client_id = 8998879 + redirect_uri = 'http://example.com/auth' + scope = 'ViewReports,CreateCampaigns,SendCampaigns' + + self.cs = CreateSend(self.oauth_auth_details) + authorize_url = self.cs.authorize_url( + client_id=client_id, + redirect_uri=redirect_uri, + scope=scope + ) + self.assertEquals(authorize_url, + "https://api.createsend.com/oauth?client_id=8998879&redirect_uri=http%3A%2F%2Fexample.com%2Fauth&scope=ViewReports%2CCreateCampaigns%2CSendCampaigns" + ) + + def test_exchange_token_success(self): + client_id = 8998879 + client_secret = 'iou0q9wud0q9wd0q9wid0q9iwd0q9wid0q9wdqwd' + redirect_uri = 'http://example.com/auth' + code = '98uqw9d8qu9wdu' + self.cs = CreateSend(self.oauth_auth_details) + self.cs.stub_request( + "https://api.createsend.com/oauth/token", "oauth_exchange_token.json") + access_token, expires_in, refresh_token = self.cs.exchange_token( + client_id=client_id, + client_secret=client_secret, + redirect_uri=redirect_uri, + code=code + ) + self.assertEquals(self.cs.faker.actual_body, + "grant_type=authorization_code&client_id=8998879&client_secret=iou0q9wud0q9wd0q9wid0q9iwd0q9wid0q9wdqwd&redirect_uri=http%3A%2F%2Fexample.com%2Fauth&code=98uqw9d8qu9wdu") + self.assertEquals(access_token, "SlAV32hkKG") + self.assertEquals(expires_in, 1209600) + self.assertEquals(refresh_token, "tGzv3JOkF0XG5Qx2TlKWIA") + + def test_echange_token_failure(self): + client_id = 8998879 + client_secret = 'iou0q9wud0q9wd0q9wid0q9iwd0q9wid0q9wdqwd' + redirect_uri = 'http://example.com/auth' + code = 'invalidcode' + self.cs = CreateSend(self.oauth_auth_details) + self.cs.stub_request( + "https://api.createsend.com/oauth/token", "oauth_exchange_token_error.json") + self.assertRaises(Exception, self.cs.exchange_token, + client_id, client_secret, redirect_uri, code) + self.assertEquals(self.cs.faker.actual_body, + "grant_type=authorization_code&client_id=8998879&client_secret=iou0q9wud0q9wd0q9wid0q9iwd0q9wid0q9wdqwd&redirect_uri=http%3A%2F%2Fexample.com%2Fauth&code=invalidcode") + + def test_can_authenticate_by_calling_auth_with_api_key(self): + self.cs = CreateSend(self.api_key_auth_details) + self.cs.stub_request("systemdate.json", "systemdate.json") + systemdate = self.cs.systemdate() + self.assertEquals(self.cs.headers['Authorization'], "Basic %s" % base64.b64encode( + ("%s:x" % self.api_key_auth_details['api_key']).encode()).decode()) + self.assertEquals(systemdate, "2010-10-15 09:27:00") + + def test_can_authenticate_by_calling_auth_with_oauth_credentials(self): + self.cs = CreateSend(self.oauth_auth_details) + self.cs.stub_request("systemdate.json", "systemdate.json") + systemdate = self.cs.systemdate() + self.assertEquals(self.cs.headers[ + 'Authorization'], "Bearer %s" % self.oauth_auth_details['access_token']) + self.assertEquals(systemdate, "2010-10-15 09:27:00") + + def test_raise_error_when_authenticating_with_oauth_and_token_expired(self): + self.cs = CreateSend(self.oauth_auth_details) + self.cs.stub_request( + "systemdate.json", 'expired_oauth_token_api_error.json', status=401) + self.assertRaises(ExpiredOAuthToken, self.cs.systemdate) + + def test_refresh_token(self): + self.cs = CreateSend(self.oauth_auth_details) + self.cs.stub_request( + "https://api.createsend.com/oauth/token", "refresh_oauth_token.json") + new_access_token, new_expires_in, new_refresh_token = self.cs.refresh_token() + + self.assertEquals(self.cs.faker.actual_body, + "grant_type=refresh_token&refresh_token=5S4aASP9R%2B9KsgfHB0dapTYxNA%3D%3D") + self.assertEquals(new_access_token, "SlAV32hkKG2e12e") + self.assertEquals(new_expires_in, 1209600) + self.assertEquals(new_refresh_token, "tGzv3JOkF0XG5Qx2TlKWIA") + self.assertEquals(self.cs.auth_details, + {'access_token': new_access_token, 'refresh_token': new_refresh_token}) + + def test_refresh_token_error_when_refresh_token_none(self): + self.cs = CreateSend( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": None}) + self.assertRaises(Exception, self.cs.refresh_token) + + def test_refresh_token_error_when_no_refresh_token_passed_in(self): + self.cs = CreateSend({"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA=="}) + self.assertRaises(Exception, self.cs.refresh_token) + + def test_refresh_token_error_when_no_authentication(self): + self.cs = CreateSend() + self.assertRaises(Exception, self.cs.refresh_token) diff --git a/test/test_campaign.py b/test/test_campaign.py index b0f8641..679497f 100644 --- a/test/test_campaign.py +++ b/test/test_campaign.py @@ -1,293 +1,338 @@ from six.moves.urllib.parse import quote import unittest -from createsend import * +from createsend.campaign import Campaign + class CampaignTestCase(object): - def test_create(self): - client_id = '87y8d7qyw8d7yq8w7ydwqwd' - c = Campaign() - c.stub_request("campaigns/%s.json" % client_id, "create_campaign.json") - campaign_id = c.create(client_id, "subject", "name", "g'day", "good.day@example.com", "good.day@example.com", - "http://example.com/campaign.html", "http://example.com/campaign.txt", [ '7y12989e82ue98u2e', 'dh9w89q8w98wudwd989' ], - [ 'y78q9w8d9w8ud9q8uw', 'djw98quw9duqw98uwd98' ]) + def test_create(self): + client_id = '87y8d7qyw8d7yq8w7ydwqwd' + c = Campaign() + c.stub_request("campaigns/%s.json" % client_id, "create_campaign.json") + campaign_id = c.create(client_id, "subject", "name", "g'day", "good.day@example.com", "good.day@example.com", + "http://example.com/campaign.html", "http://example.com/campaign.txt", [ + '7y12989e82ue98u2e', 'dh9w89q8w98wudwd989'], + ['y78q9w8d9w8ud9q8uw', 'djw98quw9duqw98uwd98']) - self.assertEquals("\"TextUrl\": \"http://example.com/campaign.txt\"" in c.faker.actual_body, True) - self.assertEquals(c.campaign_id, "787y87y87y87y87y87y8712341234") - self.assertEquals(campaign_id, "787y87y87y87y87y87y8712341234") + self.assertEquals( + "\"TextUrl\": \"http://example.com/campaign.txt\"" in c.faker.actual_body, True) + self.assertEquals(c.campaign_id, "787y87y87y87y87y87y8712341234") + self.assertEquals(campaign_id, "787y87y87y87y87y87y8712341234") - def test_create_with_none_text_url(self): - client_id = '87y8d7qyw8d7yq8w7ydwqwd' - c = Campaign() - c.stub_request("campaigns/%s.json" % client_id, "create_campaign.json") - campaign_id = c.create(client_id, "subject", "name", "g'day", "good.day@example.com", "good.day@example.com", - "http://example.com/campaign.html", None, [ '7y12989e82ue98u2e', 'dh9w89q8w98wudwd989' ], - [ 'y78q9w8d9w8ud9q8uw', 'djw98quw9duqw98uwd98' ]) + def test_create_with_none_text_url(self): + client_id = '87y8d7qyw8d7yq8w7ydwqwd' + c = Campaign() + c.stub_request("campaigns/%s.json" % client_id, "create_campaign.json") + campaign_id = c.create(client_id, "subject", "name", "g'day", "good.day@example.com", "good.day@example.com", + "http://example.com/campaign.html", None, [ + '7y12989e82ue98u2e', 'dh9w89q8w98wudwd989'], + ['y78q9w8d9w8ud9q8uw', 'djw98quw9duqw98uwd98']) - self.assertEquals("\"TextUrl\": null" in c.faker.actual_body, True) - self.assertEquals(c.campaign_id, "787y87y87y87y87y87y8712341234") - self.assertEquals(campaign_id, "787y87y87y87y87y87y8712341234") + self.assertEquals("\"TextUrl\": null" in c.faker.actual_body, True) + self.assertEquals(c.campaign_id, "787y87y87y87y87y87y8712341234") + self.assertEquals(campaign_id, "787y87y87y87y87y87y8712341234") - def test_create_from_template(self): - template_content = { - "Singlelines": [ - { - "Content": "This is a heading", - "Href": "http://example.com/" - } - ], - "Multilines": [ - { - "Content": "

This is example

multiline content...

" - } - ], - "Images": [ - { - "Content": "http://example.com/image.png", - "Alt": "This is alt text for an image", - "Href": "http://example.com/" - } - ], - "Repeaters": [ - { - "Items": [ - { - "Layout": "My layout", - "Singlelines": [ + def test_create_from_template(self): + template_content = { + "Singlelines": [ + { + "Content": "This is a heading", + "Href": "http://example.com/" + } + ], + "Multilines": [ { - "Content": "This is a repeater heading", - "Href": "http://example.com/" + "Content": "

This is example

multiline content...

" } - ], - "Multilines": [ + ], + "Images": [ { - "Content": "

This is example

multiline content...

" + "Content": "http://example.com/image.png", + "Alt": "This is alt text for an image", + "Href": "http://example.com/" } - ], - "Images": [ + ], + "Repeaters": [ { - "Content": "http://example.com/repeater-image.png", - "Alt": "This is alt text for a repeater image", - "Href": "http://example.com/" + "Items": [ + { + "Layout": "My layout", + "Singlelines": [ + { + "Content": "This is a repeater heading", + "Href": "http://example.com/" + } + ], + "Multilines": [ + { + "Content": "

This is example

multiline content...

" + } + ], + "Images": [ + { + "Content": "http://example.com/repeater-image.png", + "Alt": "This is alt text for a repeater image", + "Href": "http://example.com/" + } + ] + } + ] } - ] - } - ] + ] } - ] - } - # template_content as defined above would be used to fill the content of - # a template with markup similar to the following: - # - # - # My Template - # - #

Enter heading...

- #
Enter description...
- # - # - # - #
- #

- #
- # - #
- #
- #
- #

Unsubscribe

- # - # + # template_content as defined above would be used to fill the content of + # a template with markup similar to the following: + # + # + # My Template + # + #

Enter heading...

+ #
Enter description...
+ # + # + # + #
+ #

+ #
+ # + #
+ #
+ #
+ #

Unsubscribe

+ # + # - client_id = '87y8d7qyw8d7yq8w7ydwqwd' - c = Campaign() - c.stub_request("campaigns/%s/fromtemplate.json" % client_id, "create_campaign.json") - campaign_id = c.create_from_template(client_id, "subject", "name", "g'day", "good.day@example.com", "good.day@example.com", - [ '7y12989e82ue98u2e', 'dh9w89q8w98wudwd989' ], [ 'y78q9w8d9w8ud9q8uw', 'djw98quw9duqw98uwd98' ], - "7j8uw98udowy12989e8298u2e", template_content) - self.assertEquals(c.campaign_id, "787y87y87y87y87y87y8712341234") - self.assertEquals(campaign_id, "787y87y87y87y87y87y8712341234") + client_id = '87y8d7qyw8d7yq8w7ydwqwd' + c = Campaign() + c.stub_request("campaigns/%s/fromtemplate.json" % + client_id, "create_campaign.json") + campaign_id = c.create_from_template(client_id, "subject", "name", "g'day", "good.day@example.com", "good.day@example.com", + ['7y12989e82ue98u2e', 'dh9w89q8w98wudwd989'], [ + 'y78q9w8d9w8ud9q8uw', 'djw98quw9duqw98uwd98'], + "7j8uw98udowy12989e8298u2e", template_content) + self.assertEquals(c.campaign_id, "787y87y87y87y87y87y8712341234") + self.assertEquals(campaign_id, "787y87y87y87y87y87y8712341234") - def test_send_preview_with_single_recipient(self): - self.campaign.stub_request("campaigns/%s/sendpreview.json" % self.campaign_id, None) - self.campaign.send_preview("test+89898u9@example.com", "random") + def test_send_preview_with_single_recipient(self): + self.campaign.stub_request( + "campaigns/%s/sendpreview.json" % self.campaign_id, None) + self.campaign.send_preview("test+89898u9@example.com", "random") - def test_send_preview_with_multiple_recipients(self): - self.campaign.stub_request("campaigns/%s/sendpreview.json" % self.campaign_id, None) - self.campaign.send_preview([ "test+89898u9@example.com", "test+787y8y7y8@example.com" ], "random") + def test_send_preview_with_multiple_recipients(self): + self.campaign.stub_request( + "campaigns/%s/sendpreview.json" % self.campaign_id, None) + self.campaign.send_preview( + ["test+89898u9@example.com", "test+787y8y7y8@example.com"], "random") - def test_send(self): - self.campaign.stub_request("campaigns/%s/send.json" % self.campaign_id, None) - self.campaign.send("confirmation@example.com") + def test_send(self): + self.campaign.stub_request( + "campaigns/%s/send.json" % self.campaign_id, None) + self.campaign.send("confirmation@example.com") - def test_unschedule(self): - self.campaign.stub_request("campaigns/%s/unschedule.json" % self.campaign_id, None) - self.campaign.unschedule() + def test_unschedule(self): + self.campaign.stub_request( + "campaigns/%s/unschedule.json" % self.campaign_id, None) + self.campaign.unschedule() - def test_delete(self): - self.campaign.stub_request("campaigns/%s.json" % self.campaign_id, None) - self.campaign.delete() - - def test_summary(self): - self.campaign.stub_request("campaigns/%s/summary.json" % self.campaign_id, "campaign_summary.json") - summary = self.campaign.summary() - self.assertEquals(summary.Recipients, 5) - self.assertEquals(summary.TotalOpened, 10) - self.assertEquals(summary.Clicks, 0) - self.assertEquals(summary.Unsubscribed, 0) - self.assertEquals(summary.Bounced, 0) - self.assertEquals(summary.UniqueOpened, 5) - self.assertEquals(summary.Mentions, 23) - self.assertEquals(summary.Forwards, 11) - self.assertEquals(summary.Likes, 32) - self.assertEquals(summary.WebVersionURL, "http://createsend.com/t/r-3A433FC72FFE3B8B") - self.assertEquals(summary.WebVersionTextURL, "http://createsend.com/t/r-3A433FC72FFE3B8B/t") - self.assertEquals(summary.WorldviewURL, "http://client.createsend.com/reports/wv/r/3A433FC72FFE3B8B") - self.assertEquals(summary.SpamComplaints, 23) + def test_delete(self): + self.campaign.stub_request("campaigns/%s.json" % + self.campaign_id, None) + self.campaign.delete() - def test_email_client_usage(self): - self.campaign.stub_request("campaigns/%s/emailclientusage.json" % self.campaign_id, "email_client_usage.json") - ecu = self.campaign.email_client_usage() - self.assertEqual(len(ecu), 6) - self.assertEqual(ecu[0].Client, "iOS Devices") - self.assertEqual(ecu[0].Version, "iPhone") - self.assertEqual(ecu[0].Percentage, 19.83) - self.assertEqual(ecu[0].Subscribers, 7056) + def test_summary(self): + self.campaign.stub_request( + "campaigns/%s/summary.json" % self.campaign_id, "campaign_summary.json") + summary = self.campaign.summary() + self.assertEquals(summary.Recipients, 5) + self.assertEquals(summary.TotalOpened, 10) + self.assertEquals(summary.Clicks, 0) + self.assertEquals(summary.Unsubscribed, 0) + self.assertEquals(summary.Bounced, 0) + self.assertEquals(summary.UniqueOpened, 5) + self.assertEquals(summary.Mentions, 23) + self.assertEquals(summary.Forwards, 11) + self.assertEquals(summary.Likes, 32) + self.assertEquals(summary.WebVersionURL, + "http://createsend.com/t/r-3A433FC72FFE3B8B") + self.assertEquals(summary.WebVersionTextURL, + "http://createsend.com/t/r-3A433FC72FFE3B8B/t") + self.assertEquals( + summary.WorldviewURL, "http://client.createsend.com/reports/wv/r/3A433FC72FFE3B8B") + self.assertEquals(summary.SpamComplaints, 23) - def test_lists_and_segments(self): - self.campaign.stub_request("campaigns/%s/listsandsegments.json" % self.campaign_id, "campaign_listsandsegments.json") - ls = self.campaign.lists_and_segments() - self.assertEquals(len(ls.Lists), 1) - self.assertEquals(len(ls.Segments), 1) - self.assertEquals(ls.Lists[0].Name, "List One") - self.assertEquals(ls.Lists[0].ListID, "a58ee1d3039b8bec838e6d1482a8a965") - self.assertEquals(ls.Segments[0].Title, "Segment for campaign") - self.assertEquals(ls.Segments[0].ListID, "2bea949d0bf96148c3e6a209d2e82060") - self.assertEquals(ls.Segments[0].SegmentID, "dba84a225d5ce3d19105d7257baac46f") + def test_email_client_usage(self): + self.campaign.stub_request( + "campaigns/%s/emailclientusage.json" % self.campaign_id, "email_client_usage.json") + ecu = self.campaign.email_client_usage() + self.assertEqual(len(ecu), 6) + self.assertEqual(ecu[0].Client, "iOS Devices") + self.assertEqual(ecu[0].Version, "iPhone") + self.assertEqual(ecu[0].Percentage, 19.83) + self.assertEqual(ecu[0].Subscribers, 7056) - def test_recipients(self): - self.campaign.stub_request("campaigns/%s/recipients.json?orderfield=email&page=1&pagesize=20&orderdirection=asc" % self.campaign_id, "campaign_recipients.json") - res = self.campaign.recipients(page=1, page_size=20) - self.assertEquals(res.ResultsOrderedBy, "email") - self.assertEquals(res.OrderDirection, "asc") - self.assertEquals(res.PageNumber, 1) - self.assertEquals(res.PageSize, 20) - self.assertEquals(res.RecordsOnThisPage, 20) - self.assertEquals(res.TotalNumberOfRecords, 2200) - self.assertEquals(res.NumberOfPages, 110) - self.assertEquals(len(res.Results), 20) - self.assertEquals(res.Results[0].EmailAddress, "subs+6g76t7t0@example.com") - self.assertEquals(res.Results[0].ListID, "a994a3caf1328a16af9a69a730eaa706") + def test_lists_and_segments(self): + self.campaign.stub_request("campaigns/%s/listsandsegments.json" % + self.campaign_id, "campaign_listsandsegments.json") + ls = self.campaign.lists_and_segments() + self.assertEquals(len(ls.Lists), 1) + self.assertEquals(len(ls.Segments), 1) + self.assertEquals(ls.Lists[0].Name, "List One") + self.assertEquals(ls.Lists[0].ListID, + "a58ee1d3039b8bec838e6d1482a8a965") + self.assertEquals(ls.Segments[0].Title, "Segment for campaign") + self.assertEquals(ls.Segments[0].ListID, + "2bea949d0bf96148c3e6a209d2e82060") + self.assertEquals(ls.Segments[0].SegmentID, + "dba84a225d5ce3d19105d7257baac46f") - def test_opens(self): - min_date = "2010-01-01" - self.campaign.stub_request("campaigns/%s/opens.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % (self.campaign_id, quote(min_date, '')), "campaign_opens.json") - opens = self.campaign.opens(min_date) - self.assertEquals(len(opens.Results), 5) - self.assertEquals(opens.Results[0].EmailAddress, "subs+6576576576@example.com") - self.assertEquals(opens.Results[0].ListID, "512a3bc577a58fdf689c654329b50fa0") - self.assertEquals(opens.Results[0].Date, "2010-10-11 08:29:00") - self.assertEquals(opens.Results[0].IPAddress, "192.168.126.87") - self.assertEquals(opens.Results[0].Latitude, -33.8683) - self.assertEquals(opens.Results[0].Longitude, 151.2086) - self.assertEquals(opens.Results[0].City, "Sydney") - self.assertEquals(opens.Results[0].Region, "New South Wales") - self.assertEquals(opens.Results[0].CountryCode, "AU") - self.assertEquals(opens.Results[0].CountryName, "Australia") - self.assertEquals(opens.ResultsOrderedBy, "date") - self.assertEquals(opens.OrderDirection, "asc") - self.assertEquals(opens.PageNumber, 1) - self.assertEquals(opens.PageSize, 1000) - self.assertEquals(opens.RecordsOnThisPage, 5) - self.assertEquals(opens.TotalNumberOfRecords, 5) - self.assertEquals(opens.NumberOfPages, 1) + def test_recipients(self): + self.campaign.stub_request("campaigns/%s/recipients.json?orderfield=email&page=1&pagesize=20&orderdirection=asc" % + self.campaign_id, "campaign_recipients.json") + res = self.campaign.recipients(page=1, page_size=20) + self.assertEquals(res.ResultsOrderedBy, "email") + self.assertEquals(res.OrderDirection, "asc") + self.assertEquals(res.PageNumber, 1) + self.assertEquals(res.PageSize, 20) + self.assertEquals(res.RecordsOnThisPage, 20) + self.assertEquals(res.TotalNumberOfRecords, 2200) + self.assertEquals(res.NumberOfPages, 110) + self.assertEquals(len(res.Results), 20) + self.assertEquals(res.Results[0].EmailAddress, + "subs+6g76t7t0@example.com") + self.assertEquals(res.Results[0].ListID, + "a994a3caf1328a16af9a69a730eaa706") - def test_clicks(self): - min_date = "2010-01-01" - self.campaign.stub_request("campaigns/%s/clicks.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % (self.campaign_id, quote(min_date, '')), "campaign_clicks.json") - clicks = self.campaign.clicks(min_date) - self.assertEquals(len(clicks.Results), 3) - self.assertEquals(clicks.Results[0].EmailAddress, "subs+6576576576@example.com") - self.assertEquals(clicks.Results[0].URL, "http://video.google.com.au/?hl=en&tab=wv") - self.assertEquals(clicks.Results[0].ListID, "512a3bc577a58fdf689c654329b50fa0") - self.assertEquals(clicks.Results[0].Date, "2010-10-11 08:29:00") - self.assertEquals(clicks.Results[0].IPAddress, "192.168.126.87") - self.assertEquals(clicks.Results[0].Latitude, -33.8683) - self.assertEquals(clicks.Results[0].Longitude, 151.2086) - self.assertEquals(clicks.Results[0].City, "Sydney") - self.assertEquals(clicks.Results[0].Region, "New South Wales") - self.assertEquals(clicks.Results[0].CountryCode, "AU") - self.assertEquals(clicks.Results[0].CountryName, "Australia") - self.assertEquals(clicks.ResultsOrderedBy, "date") - self.assertEquals(clicks.OrderDirection, "asc") - self.assertEquals(clicks.PageNumber, 1) - self.assertEquals(clicks.PageSize, 1000) - self.assertEquals(clicks.RecordsOnThisPage, 3) - self.assertEquals(clicks.TotalNumberOfRecords, 3) - self.assertEquals(clicks.NumberOfPages, 1) + def test_opens(self): + min_date = "2010-01-01" + self.campaign.stub_request("campaigns/%s/opens.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % + (self.campaign_id, quote(min_date, '')), "campaign_opens.json") + opens = self.campaign.opens(min_date) + self.assertEquals(len(opens.Results), 5) + self.assertEquals( + opens.Results[0].EmailAddress, "subs+6576576576@example.com") + self.assertEquals(opens.Results[0].ListID, + "512a3bc577a58fdf689c654329b50fa0") + self.assertEquals(opens.Results[0].Date, "2010-10-11 08:29:00") + self.assertEquals(opens.Results[0].IPAddress, "192.168.126.87") + self.assertEquals(opens.Results[0].Latitude, -33.8683) + self.assertEquals(opens.Results[0].Longitude, 151.2086) + self.assertEquals(opens.Results[0].City, "Sydney") + self.assertEquals(opens.Results[0].Region, "New South Wales") + self.assertEquals(opens.Results[0].CountryCode, "AU") + self.assertEquals(opens.Results[0].CountryName, "Australia") + self.assertEquals(opens.ResultsOrderedBy, "date") + self.assertEquals(opens.OrderDirection, "asc") + self.assertEquals(opens.PageNumber, 1) + self.assertEquals(opens.PageSize, 1000) + self.assertEquals(opens.RecordsOnThisPage, 5) + self.assertEquals(opens.TotalNumberOfRecords, 5) + self.assertEquals(opens.NumberOfPages, 1) - def test_unsubscribes(self): - min_date = "2010-01-01" - self.campaign.stub_request("campaigns/%s/unsubscribes.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % (self.campaign_id, quote(min_date, '')), "campaign_unsubscribes.json") - unsubscribes = self.campaign.unsubscribes(min_date) - self.assertEquals(len(unsubscribes.Results), 1) - self.assertEquals(unsubscribes.Results[0].EmailAddress, "subs+6576576576@example.com") - self.assertEquals(unsubscribes.Results[0].ListID, "512a3bc577a58fdf689c654329b50fa0") - self.assertEquals(unsubscribes.Results[0].Date, "2010-10-11 08:29:00") - self.assertEquals(unsubscribes.Results[0].IPAddress, "192.168.126.87") - self.assertEquals(unsubscribes.ResultsOrderedBy, "date") - self.assertEquals(unsubscribes.OrderDirection, "asc") - self.assertEquals(unsubscribes.PageNumber, 1) - self.assertEquals(unsubscribes.PageSize, 1000) - self.assertEquals(unsubscribes.RecordsOnThisPage, 1) - self.assertEquals(unsubscribes.TotalNumberOfRecords, 1) - self.assertEquals(unsubscribes.NumberOfPages, 1) + def test_clicks(self): + min_date = "2010-01-01" + self.campaign.stub_request("campaigns/%s/clicks.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % + (self.campaign_id, quote(min_date, '')), "campaign_clicks.json") + clicks = self.campaign.clicks(min_date) + self.assertEquals(len(clicks.Results), 3) + self.assertEquals( + clicks.Results[0].EmailAddress, "subs+6576576576@example.com") + self.assertEquals( + clicks.Results[0].URL, "http://video.google.com.au/?hl=en&tab=wv") + self.assertEquals( + clicks.Results[0].ListID, "512a3bc577a58fdf689c654329b50fa0") + self.assertEquals(clicks.Results[0].Date, "2010-10-11 08:29:00") + self.assertEquals(clicks.Results[0].IPAddress, "192.168.126.87") + self.assertEquals(clicks.Results[0].Latitude, -33.8683) + self.assertEquals(clicks.Results[0].Longitude, 151.2086) + self.assertEquals(clicks.Results[0].City, "Sydney") + self.assertEquals(clicks.Results[0].Region, "New South Wales") + self.assertEquals(clicks.Results[0].CountryCode, "AU") + self.assertEquals(clicks.Results[0].CountryName, "Australia") + self.assertEquals(clicks.ResultsOrderedBy, "date") + self.assertEquals(clicks.OrderDirection, "asc") + self.assertEquals(clicks.PageNumber, 1) + self.assertEquals(clicks.PageSize, 1000) + self.assertEquals(clicks.RecordsOnThisPage, 3) + self.assertEquals(clicks.TotalNumberOfRecords, 3) + self.assertEquals(clicks.NumberOfPages, 1) - def test_spam(self): - min_date = "2010-01-01" - self.campaign.stub_request("campaigns/%s/spam.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % (self.campaign_id, quote(min_date, '')), "campaign_spam.json") - spam = self.campaign.spam(min_date) - self.assertEquals(len(spam.Results), 1) - self.assertEquals(spam.Results[0].EmailAddress, "subs+6576576576@example.com") - self.assertEquals(spam.Results[0].ListID, "512a3bc577a58fdf689c654329b50fa0") - self.assertEquals(spam.Results[0].Date, "2010-10-11 08:29:00") - self.assertEquals(spam.ResultsOrderedBy, "date") - self.assertEquals(spam.OrderDirection, "asc") - self.assertEquals(spam.PageNumber, 1) - self.assertEquals(spam.PageSize, 1000) - self.assertEquals(spam.RecordsOnThisPage, 1) - self.assertEquals(spam.TotalNumberOfRecords, 1) - self.assertEquals(spam.NumberOfPages, 1) + def test_unsubscribes(self): + min_date = "2010-01-01" + self.campaign.stub_request("campaigns/%s/unsubscribes.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % + (self.campaign_id, quote(min_date, '')), "campaign_unsubscribes.json") + unsubscribes = self.campaign.unsubscribes(min_date) + self.assertEquals(len(unsubscribes.Results), 1) + self.assertEquals(unsubscribes.Results[ + 0].EmailAddress, "subs+6576576576@example.com") + self.assertEquals(unsubscribes.Results[ + 0].ListID, "512a3bc577a58fdf689c654329b50fa0") + self.assertEquals(unsubscribes.Results[0].Date, "2010-10-11 08:29:00") + self.assertEquals(unsubscribes.Results[0].IPAddress, "192.168.126.87") + self.assertEquals(unsubscribes.ResultsOrderedBy, "date") + self.assertEquals(unsubscribes.OrderDirection, "asc") + self.assertEquals(unsubscribes.PageNumber, 1) + self.assertEquals(unsubscribes.PageSize, 1000) + self.assertEquals(unsubscribes.RecordsOnThisPage, 1) + self.assertEquals(unsubscribes.TotalNumberOfRecords, 1) + self.assertEquals(unsubscribes.NumberOfPages, 1) + + def test_spam(self): + min_date = "2010-01-01" + self.campaign.stub_request("campaigns/%s/spam.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % + (self.campaign_id, quote(min_date, '')), "campaign_spam.json") + spam = self.campaign.spam(min_date) + self.assertEquals(len(spam.Results), 1) + self.assertEquals( + spam.Results[0].EmailAddress, "subs+6576576576@example.com") + self.assertEquals(spam.Results[0].ListID, + "512a3bc577a58fdf689c654329b50fa0") + self.assertEquals(spam.Results[0].Date, "2010-10-11 08:29:00") + self.assertEquals(spam.ResultsOrderedBy, "date") + self.assertEquals(spam.OrderDirection, "asc") + self.assertEquals(spam.PageNumber, 1) + self.assertEquals(spam.PageSize, 1000) + self.assertEquals(spam.RecordsOnThisPage, 1) + self.assertEquals(spam.TotalNumberOfRecords, 1) + self.assertEquals(spam.NumberOfPages, 1) + + def test_bounces(self): + min_date = "2010-01-01" + self.campaign.stub_request("campaigns/%s/bounces.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % + (self.campaign_id, quote(min_date, '')), "campaign_bounces.json") + bounces = self.campaign.bounces(min_date) + self.assertEquals(len(bounces.Results), 2) + self.assertEquals( + bounces.Results[0].EmailAddress, "asdf@softbouncemyemail.com") + self.assertEquals( + bounces.Results[0].ListID, "654523a5855b4a440bae3fb295641546") + self.assertEquals(bounces.Results[0].BounceType, "Soft") + self.assertEquals(bounces.Results[0].Date, "2010-07-02 16:46:00") + self.assertEquals( + bounces.Results[0].Reason, "Bounce - But No Email Address Returned ") + self.assertEquals(bounces.ResultsOrderedBy, "date") + self.assertEquals(bounces.OrderDirection, "asc") + self.assertEquals(bounces.PageNumber, 1) + self.assertEquals(bounces.PageSize, 1000) + self.assertEquals(bounces.RecordsOnThisPage, 2) + self.assertEquals(bounces.TotalNumberOfRecords, 2) + self.assertEquals(bounces.NumberOfPages, 1) - def test_bounces(self): - min_date = "2010-01-01" - self.campaign.stub_request("campaigns/%s/bounces.json?date=%s&orderfield=date&page=1&pagesize=1000&orderdirection=asc" % (self.campaign_id, quote(min_date, '')), "campaign_bounces.json") - bounces = self.campaign.bounces(min_date) - self.assertEquals(len(bounces.Results), 2) - self.assertEquals(bounces.Results[0].EmailAddress, "asdf@softbouncemyemail.com") - self.assertEquals(bounces.Results[0].ListID, "654523a5855b4a440bae3fb295641546") - self.assertEquals(bounces.Results[0].BounceType, "Soft") - self.assertEquals(bounces.Results[0].Date, "2010-07-02 16:46:00") - self.assertEquals(bounces.Results[0].Reason, "Bounce - But No Email Address Returned ") - self.assertEquals(bounces.ResultsOrderedBy, "date") - self.assertEquals(bounces.OrderDirection, "asc") - self.assertEquals(bounces.PageNumber, 1) - self.assertEquals(bounces.PageSize, 1000) - self.assertEquals(bounces.RecordsOnThisPage, 2) - self.assertEquals(bounces.TotalNumberOfRecords, 2) - self.assertEquals(bounces.NumberOfPages, 1) class OAuthCampaignTestCase(unittest.TestCase, CampaignTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.campaign_id = "787y87y87y87y87y87y87" - self.campaign = Campaign( - {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, self.campaign_id) + """Test when using OAuth to authenticate""" + + def setUp(self): + self.campaign_id = "787y87y87y87y87y87y87" + self.campaign = Campaign( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, self.campaign_id) + class ApiKeyCampaignTestCase(unittest.TestCase, CampaignTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.campaign_id = "787y87y87y87y87y87y87" - self.campaign = Campaign( - {'api_key': '123123123123123123123'}, self.campaign_id) + """Test when using an API key to authenticate""" + + def setUp(self): + self.campaign_id = "787y87y87y87y87y87y87" + self.campaign = Campaign( + {'api_key': '123123123123123123123'}, self.campaign_id) diff --git a/test/test_client.py b/test/test_client.py index bdbf366..3477ac5 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -1,190 +1,233 @@ from six.moves.urllib.parse import quote import unittest -from createsend import * +from createsend.client import Client + class ClientTestCase(object): - def test_create(self): - c = Client() - c.stub_request("clients.json", "create_client.json") - client_id = c.create("Client Company Name", "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") - self.assertEquals("32a381c49a2df99f1d0c6f3c112352b9", client_id) - self.assertEquals("32a381c49a2df99f1d0c6f3c112352b9", c.client_id) - - def test_details(self): - self.cl.stub_request("clients/%s.json" % self.cl.client_id, "client_details.json") - cl = self.cl.details() - self.assertEquals(cl.ApiKey, "639d8cc27198202f5fe6037a8b17a29a59984b86d3289bc9") - self.assertEquals(cl.BasicDetails.ClientID, "4a397ccaaa55eb4e6aa1221e1e2d7122") - self.assertEquals(cl.BasicDetails.ContactName, "Client One (contact)") - self.assertEquals(cl.AccessDetails.Username, "clientone") - self.assertEquals(cl.AccessDetails.AccessLevel, 23) - self.assertEquals(cl.BillingDetails.Credits, 500) - - def test_campaigns(self): - self.cl.stub_request("clients/%s/campaigns.json" % self.cl.client_id, "campaigns.json") - campaigns = self.cl.campaigns() - self.assertEquals(len(campaigns), 2) - self.assertEquals(campaigns[0].CampaignID, 'fc0ce7105baeaf97f47c99be31d02a91') - self.assertEquals(campaigns[0].WebVersionURL, 'http://createsend.com/t/r-765E86829575EE2C') - self.assertEquals(campaigns[0].WebVersionTextURL, 'http://createsend.com/t/r-765E86829575EE2C/t') - self.assertEquals(campaigns[0].Subject, 'Campaign One') - self.assertEquals(campaigns[0].Name, 'Campaign One') - self.assertEquals(campaigns[0].SentDate, '2010-10-12 12:58:00') - self.assertEquals(campaigns[0].TotalRecipients, 2245) - self.assertEquals(campaigns[0].FromName, 'My Name') - self.assertEquals(campaigns[0].FromEmail, 'myemail@example.com') - self.assertEquals(campaigns[0].ReplyTo, 'myemail@example.com') - - def test_scheduled(self): - self.cl.stub_request("clients/%s/scheduled.json" % self.cl.client_id, "scheduled_campaigns.json") - campaigns = self.cl.scheduled() - self.assertEquals(len(campaigns), 2) - self.assertEquals(campaigns[0].DateScheduled, "2011-05-25 10:40:00") - self.assertEquals(campaigns[0].ScheduledTimeZone, "(GMT+10:00) Canberra, Melbourne, Sydney") - self.assertEquals(campaigns[0].CampaignID, "827dbbd2161ea9989fa11ad562c66937") - self.assertEquals(campaigns[0].Name, "Magic Issue One") - self.assertEquals(campaigns[0].Subject, "Magic Issue One") - self.assertEquals(campaigns[0].DateCreated, "2011-05-24 10:37:00") - self.assertEquals(campaigns[0].PreviewURL, "http://createsend.com/t/r-DD543521A87C9B8B") - self.assertEquals(campaigns[0].PreviewTextURL, "http://createsend.com/t/r-DD543521A87C9B8B/t") - self.assertEquals(campaigns[0].FromName, 'My Name') - self.assertEquals(campaigns[0].FromEmail, 'myemail@example.com') - self.assertEquals(campaigns[0].ReplyTo, 'myemail@example.com') - - def test_drafts(self): - self.cl.stub_request("clients/%s/drafts.json" % self.cl.client_id, "drafts.json") - drafts = self.cl.drafts() - self.assertEquals(len(drafts), 2) - self.assertEquals(drafts[0].CampaignID, '7c7424792065d92627139208c8c01db1') - self.assertEquals(drafts[0].Name, 'Draft One') - self.assertEquals(drafts[0].Subject, 'Draft One') - self.assertEquals(drafts[0].DateCreated, '2010-08-19 16:08:00') - self.assertEquals(drafts[0].PreviewURL, 'http://createsend.com/t/r-E97A7BB2E6983DA1') - self.assertEquals(drafts[0].PreviewTextURL, 'http://createsend.com/t/r-E97A7BB2E6983DA1/t') - self.assertEquals(drafts[0].FromName, 'My Name') - self.assertEquals(drafts[0].FromEmail, 'myemail@example.com') - self.assertEquals(drafts[0].ReplyTo, 'myemail@example.com') - - def test_lists(self): - self.cl.stub_request("clients/%s/lists.json" % self.cl.client_id, "lists.json") - lists = self.cl.lists() - self.assertEquals(len(lists), 2) - self.assertEquals(lists[0].ListID, 'a58ee1d3039b8bec838e6d1482a8a965') - self.assertEquals(lists[0].Name, 'List One') - - def test_lists_for_email(self): - email = "valid@example.com" - self.cl.stub_request("clients/%s/listsforemail.json?email=%s" % (self.cl.client_id, quote(email)), "listsforemail.json") - lists = self.cl.lists_for_email(email) - self.assertEquals(len(lists), 2) - self.assertEquals(lists[0].ListID, 'ab4a2b57c7c8f1ba62f898a1af1a575b') - self.assertEquals(lists[0].ListName, 'List Number One') - self.assertEquals(lists[0].SubscriberState, 'Active') - self.assertEquals(lists[0].DateSubscriberAdded, '2012-08-20 22:32:00') - - def test_segments(self): - self.cl.stub_request("clients/%s/segments.json" % self.cl.client_id, "segments.json") - segments = self.cl.segments() - self.assertEquals(len(segments), 2) - self.assertEquals(segments[0].ListID, 'a58ee1d3039b8bec838e6d1482a8a965') - self.assertEquals(segments[0].SegmentID, '46aa5e01fd43381863d4e42cf277d3a9') - self.assertEquals(segments[0].Title, 'Segment One') - - def test_suppressionlist(self): - self.cl.stub_request("clients/%s/suppressionlist.json?orderfield=email&page=1&pagesize=1000&orderdirection=asc" % self.cl.client_id, "suppressionlist.json") - res = self.cl.suppressionlist() - self.assertEquals(res.ResultsOrderedBy, "email") - self.assertEquals(res.OrderDirection, "asc") - self.assertEquals(res.PageNumber, 1) - self.assertEquals(res.PageSize, 1000) - self.assertEquals(res.RecordsOnThisPage, 5) - self.assertEquals(res.TotalNumberOfRecords, 5) - self.assertEquals(res.NumberOfPages, 1) - self.assertEquals(len(res.Results), 5) - self.assertEquals(res.Results[0].SuppressionReason, "Unsubscribed") - self.assertEquals(res.Results[0].EmailAddress, "example+1@example.com") - self.assertEquals(res.Results[0].Date, "2010-10-26 10:55:31") - self.assertEquals(res.Results[0].State, "Suppressed") - - def test_suppress_with_single_email(self): - self.cl.stub_request("clients/%s/suppress.json" % self.cl.client_id, None) - self.cl.suppress("example@example.com") - - def test_suppress_with_multiple_emails(self): - self.cl.stub_request("clients/%s/suppress.json" % self.cl.client_id, None) - self.cl.suppress(["one@example.com", "two@example.com"]) - - def test_unsuppress(self): - email = "example@example.com" - self.cl.stub_request("clients/%s/unsuppress.json?email=%s" % (self.cl.client_id, quote(email)), None) - res = self.cl.unsuppress(email) - - def test_templates(self): - self.cl.stub_request("clients/%s/templates.json" % self.cl.client_id, "templates.json") - templates = self.cl.templates() - self.assertEquals(len(templates), 2) - self.assertEquals(templates[0].TemplateID, '5cac213cf061dd4e008de5a82b7a3621') - self.assertEquals(templates[0].Name, 'Template One') - - def test_set_basics(self): - self.cl.stub_request("clients/%s/setbasics.json" % self.cl.client_id, None) - self.cl.set_basics("Client Company Name", "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") - - def test_set_payg_billing(self): - self.cl.stub_request("clients/%s/setpaygbilling.json" % self.cl.client_id, None) - self.cl.set_payg_billing("CAD", True, True, 150) - - def test_set_monthly_billing_implicit(self): - self.cl.stub_request("clients/%s/setmonthlybilling.json" % self.cl.client_id, None, None, "{\"Currency\": \"CAD\", \"MarkupPercentage\": 150, \"ClientPays\": true}") - self.cl.set_monthly_billing("CAD", True, 150) - - def test_set_monthly_billing_basic(self): - self.cl.stub_request("clients/%s/setmonthlybilling.json" % self.cl.client_id, None, None, "{\"Currency\": \"CAD\", \"MonthlyScheme\": \"Basic\", \"MarkupPercentage\": 120, \"ClientPays\": false}") - self.cl.set_monthly_billing("CAD", False, 120, "Basic") - - def test_set_monthly_billing_unlimited(self): - self.cl.stub_request("clients/%s/setmonthlybilling.json" % self.cl.client_id, None, None, "{\"Currency\": \"CAD\", \"MonthlyScheme\": \"Unlimited\", \"MarkupPercentage\": 100, \"ClientPays\": true}") - self.cl.set_monthly_billing("CAD", True, 100, "Unlimited") - - def test_transfer_credits(self): - self.cl.stub_request("clients/%s/credits.json" % self.cl.client_id, "transfer_credits.json") - result = self.cl.transfer_credits(200, False) - self.assertEquals(result.AccountCredits, 800) - self.assertEquals(result.ClientCredits, 200) - - def test_people(self): - self.cl.stub_request("clients/%s/people.json" % self.cl.client_id, "people.json") - people = self.cl.people() - self.assertEquals(2, len(people)) - self.assertEquals('person1@blackhole.com', people[0].EmailAddress) - self.assertEquals('Person One', people[0].Name) - self.assertEquals('Active', people[0].Status) - - def test_get_primary_contact(self): - self.cl.stub_request("clients/%s/primarycontact.json" % self.cl.client_id, "client_get_primary_contact.json") - primary_contact = self.cl.get_primary_contact() - self.assertEquals('person@blackhole.com', primary_contact.EmailAddress) - - def test_set_primary_contact(self): - email = 'person@blackhole.com' - self.cl.stub_request("clients/%s/primarycontact.json?email=%s" % (self.cl.client_id, quote(email, '')), 'client_set_primary_contact.json') - result = self.cl.set_primary_contact(email) - self.assertEquals(email, result.EmailAddress) - - def test_delete(self): - self.cl.stub_request("clients/%s.json" % self.cl.client_id, None) - self.cl.delete() + def test_create(self): + c = Client() + c.stub_request("clients.json", "create_client.json") + client_id = c.create( + "Client Company Name", "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") + self.assertEquals("32a381c49a2df99f1d0c6f3c112352b9", client_id) + self.assertEquals("32a381c49a2df99f1d0c6f3c112352b9", c.client_id) + + def test_details(self): + self.cl.stub_request("clients/%s.json" % + self.cl.client_id, "client_details.json") + cl = self.cl.details() + self.assertEquals( + cl.ApiKey, "639d8cc27198202f5fe6037a8b17a29a59984b86d3289bc9") + self.assertEquals(cl.BasicDetails.ClientID, + "4a397ccaaa55eb4e6aa1221e1e2d7122") + self.assertEquals(cl.BasicDetails.ContactName, "Client One (contact)") + self.assertEquals(cl.AccessDetails.Username, "clientone") + self.assertEquals(cl.AccessDetails.AccessLevel, 23) + self.assertEquals(cl.BillingDetails.Credits, 500) + + def test_campaigns(self): + self.cl.stub_request("clients/%s/campaigns.json" % + self.cl.client_id, "campaigns.json") + campaigns = self.cl.campaigns() + self.assertEquals(len(campaigns), 2) + self.assertEquals(campaigns[0].CampaignID, + 'fc0ce7105baeaf97f47c99be31d02a91') + self.assertEquals(campaigns[0].WebVersionURL, + 'http://createsend.com/t/r-765E86829575EE2C') + self.assertEquals(campaigns[0].WebVersionTextURL, + 'http://createsend.com/t/r-765E86829575EE2C/t') + self.assertEquals(campaigns[0].Subject, 'Campaign One') + self.assertEquals(campaigns[0].Name, 'Campaign One') + self.assertEquals(campaigns[0].SentDate, '2010-10-12 12:58:00') + self.assertEquals(campaigns[0].TotalRecipients, 2245) + self.assertEquals(campaigns[0].FromName, 'My Name') + self.assertEquals(campaigns[0].FromEmail, 'myemail@example.com') + self.assertEquals(campaigns[0].ReplyTo, 'myemail@example.com') + + def test_scheduled(self): + self.cl.stub_request("clients/%s/scheduled.json" % + self.cl.client_id, "scheduled_campaigns.json") + campaigns = self.cl.scheduled() + self.assertEquals(len(campaigns), 2) + self.assertEquals(campaigns[0].DateScheduled, "2011-05-25 10:40:00") + self.assertEquals(campaigns[0].ScheduledTimeZone, + "(GMT+10:00) Canberra, Melbourne, Sydney") + self.assertEquals(campaigns[0].CampaignID, + "827dbbd2161ea9989fa11ad562c66937") + self.assertEquals(campaigns[0].Name, "Magic Issue One") + self.assertEquals(campaigns[0].Subject, "Magic Issue One") + self.assertEquals(campaigns[0].DateCreated, "2011-05-24 10:37:00") + self.assertEquals(campaigns[0].PreviewURL, + "http://createsend.com/t/r-DD543521A87C9B8B") + self.assertEquals(campaigns[0].PreviewTextURL, + "http://createsend.com/t/r-DD543521A87C9B8B/t") + self.assertEquals(campaigns[0].FromName, 'My Name') + self.assertEquals(campaigns[0].FromEmail, 'myemail@example.com') + self.assertEquals(campaigns[0].ReplyTo, 'myemail@example.com') + + def test_drafts(self): + self.cl.stub_request("clients/%s/drafts.json" % + self.cl.client_id, "drafts.json") + drafts = self.cl.drafts() + self.assertEquals(len(drafts), 2) + self.assertEquals(drafts[0].CampaignID, + '7c7424792065d92627139208c8c01db1') + self.assertEquals(drafts[0].Name, 'Draft One') + self.assertEquals(drafts[0].Subject, 'Draft One') + self.assertEquals(drafts[0].DateCreated, '2010-08-19 16:08:00') + self.assertEquals(drafts[0].PreviewURL, + 'http://createsend.com/t/r-E97A7BB2E6983DA1') + self.assertEquals(drafts[0].PreviewTextURL, + 'http://createsend.com/t/r-E97A7BB2E6983DA1/t') + self.assertEquals(drafts[0].FromName, 'My Name') + self.assertEquals(drafts[0].FromEmail, 'myemail@example.com') + self.assertEquals(drafts[0].ReplyTo, 'myemail@example.com') + + def test_lists(self): + self.cl.stub_request("clients/%s/lists.json" % + self.cl.client_id, "lists.json") + lists = self.cl.lists() + self.assertEquals(len(lists), 2) + self.assertEquals(lists[0].ListID, 'a58ee1d3039b8bec838e6d1482a8a965') + self.assertEquals(lists[0].Name, 'List One') + + def test_lists_for_email(self): + email = "valid@example.com" + self.cl.stub_request("clients/%s/listsforemail.json?email=%s" % + (self.cl.client_id, quote(email)), "listsforemail.json") + lists = self.cl.lists_for_email(email) + self.assertEquals(len(lists), 2) + self.assertEquals(lists[0].ListID, 'ab4a2b57c7c8f1ba62f898a1af1a575b') + self.assertEquals(lists[0].ListName, 'List Number One') + self.assertEquals(lists[0].SubscriberState, 'Active') + self.assertEquals(lists[0].DateSubscriberAdded, '2012-08-20 22:32:00') + + def test_segments(self): + self.cl.stub_request("clients/%s/segments.json" % + self.cl.client_id, "segments.json") + segments = self.cl.segments() + self.assertEquals(len(segments), 2) + self.assertEquals(segments[0].ListID, + 'a58ee1d3039b8bec838e6d1482a8a965') + self.assertEquals(segments[0].SegmentID, + '46aa5e01fd43381863d4e42cf277d3a9') + self.assertEquals(segments[0].Title, 'Segment One') + + def test_suppressionlist(self): + self.cl.stub_request("clients/%s/suppressionlist.json?orderfield=email&page=1&pagesize=1000&orderdirection=asc" % + self.cl.client_id, "suppressionlist.json") + res = self.cl.suppressionlist() + self.assertEquals(res.ResultsOrderedBy, "email") + self.assertEquals(res.OrderDirection, "asc") + self.assertEquals(res.PageNumber, 1) + self.assertEquals(res.PageSize, 1000) + self.assertEquals(res.RecordsOnThisPage, 5) + self.assertEquals(res.TotalNumberOfRecords, 5) + self.assertEquals(res.NumberOfPages, 1) + self.assertEquals(len(res.Results), 5) + self.assertEquals(res.Results[0].SuppressionReason, "Unsubscribed") + self.assertEquals(res.Results[0].EmailAddress, "example+1@example.com") + self.assertEquals(res.Results[0].Date, "2010-10-26 10:55:31") + self.assertEquals(res.Results[0].State, "Suppressed") + + def test_suppress_with_single_email(self): + self.cl.stub_request("clients/%s/suppress.json" % + self.cl.client_id, None) + self.cl.suppress("example@example.com") + + def test_suppress_with_multiple_emails(self): + self.cl.stub_request("clients/%s/suppress.json" % + self.cl.client_id, None) + self.cl.suppress(["one@example.com", "two@example.com"]) + + def test_unsuppress(self): + email = "example@example.com" + self.cl.stub_request("clients/%s/unsuppress.json?email=%s" % + (self.cl.client_id, quote(email)), None) + res = self.cl.unsuppress(email) + + def test_templates(self): + self.cl.stub_request("clients/%s/templates.json" % + self.cl.client_id, "templates.json") + templates = self.cl.templates() + self.assertEquals(len(templates), 2) + self.assertEquals(templates[0].TemplateID, + '5cac213cf061dd4e008de5a82b7a3621') + self.assertEquals(templates[0].Name, 'Template One') + + def test_set_basics(self): + self.cl.stub_request("clients/%s/setbasics.json" % + self.cl.client_id, None) + self.cl.set_basics( + "Client Company Name", "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") + + def test_set_payg_billing(self): + self.cl.stub_request("clients/%s/setpaygbilling.json" % + self.cl.client_id, None) + self.cl.set_payg_billing("CAD", True, True, 150) + + def test_set_monthly_billing_implicit(self): + self.cl.stub_request("clients/%s/setmonthlybilling.json" % self.cl.client_id, None, + None, "{\"Currency\": \"CAD\", \"MarkupPercentage\": 150, \"ClientPays\": true}") + self.cl.set_monthly_billing("CAD", True, 150) + + def test_set_monthly_billing_basic(self): + self.cl.stub_request("clients/%s/setmonthlybilling.json" % self.cl.client_id, None, None, + "{\"Currency\": \"CAD\", \"MonthlyScheme\": \"Basic\", \"MarkupPercentage\": 120, \"ClientPays\": false}") + self.cl.set_monthly_billing("CAD", False, 120, "Basic") + + def test_set_monthly_billing_unlimited(self): + self.cl.stub_request("clients/%s/setmonthlybilling.json" % self.cl.client_id, None, None, + "{\"Currency\": \"CAD\", \"MonthlyScheme\": \"Unlimited\", \"MarkupPercentage\": 100, \"ClientPays\": true}") + self.cl.set_monthly_billing("CAD", True, 100, "Unlimited") + + def test_transfer_credits(self): + self.cl.stub_request("clients/%s/credits.json" % + self.cl.client_id, "transfer_credits.json") + result = self.cl.transfer_credits(200, False) + self.assertEquals(result.AccountCredits, 800) + self.assertEquals(result.ClientCredits, 200) + + def test_people(self): + self.cl.stub_request("clients/%s/people.json" % + self.cl.client_id, "people.json") + people = self.cl.people() + self.assertEquals(2, len(people)) + self.assertEquals('person1@blackhole.com', people[0].EmailAddress) + self.assertEquals('Person One', people[0].Name) + self.assertEquals('Active', people[0].Status) + + def test_get_primary_contact(self): + self.cl.stub_request("clients/%s/primarycontact.json" % + self.cl.client_id, "client_get_primary_contact.json") + primary_contact = self.cl.get_primary_contact() + self.assertEquals('person@blackhole.com', primary_contact.EmailAddress) + + def test_set_primary_contact(self): + email = 'person@blackhole.com' + self.cl.stub_request("clients/%s/primarycontact.json?email=%s" % + (self.cl.client_id, quote(email, '')), 'client_set_primary_contact.json') + result = self.cl.set_primary_contact(email) + self.assertEquals(email, result.EmailAddress) + + def test_delete(self): + self.cl.stub_request("clients/%s.json" % self.cl.client_id, None) + self.cl.delete() + class OAuthClientTestCase(unittest.TestCase, ClientTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.cl = Client( - {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, "4a397ccaaa55eb4e6aa1221e1e2d7122") + """Test when using OAuth to authenticate""" + + def setUp(self): + self.cl = Client( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, "4a397ccaaa55eb4e6aa1221e1e2d7122") + class ApiKeyClientTestCase(unittest.TestCase, ClientTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.cl = Client( - {'api_key': '123123123123123123123'}, "4a397ccaaa55eb4e6aa1221e1e2d7122") + """Test when using an API key to authenticate""" + + def setUp(self): + self.cl = Client( + {'api_key': '123123123123123123123'}, "4a397ccaaa55eb4e6aa1221e1e2d7122") diff --git a/test/test_createsend.py b/test/test_createsend.py index c6a7708..787604e 100644 --- a/test/test_createsend.py +++ b/test/test_createsend.py @@ -1,235 +1,275 @@ -from six.moves.urllib.parse import quote, urlparse +from six.moves.urllib.parse import quote import unittest -from createsend import * +from createsend.createsend import ( + CreateSend, + BadRequest, + Unauthorized, + NotFound, + ClientError, + ServerError +) +from createsend.client import Client +from createsend.template import Template + class CreateSendTestCase(object): - """CreateSend tests to be run in the context of both using an API key - and using OAuth.""" - - def test_that_default_user_agent_is_set(self): - self.cs.stub_request("clients.json", "clients.json") - cl = self.cs.clients() - self.assertEquals(self.cs.headers['User-Agent'], CreateSend.default_user_agent) - self.assertEquals(2, len(cl)) - - def test_that_custom_user_agent_can_be_set(self): - CreateSend.user_agent = "custom user agent" - self.cs.stub_request("clients.json", "clients.json") - cl = self.cs.clients() - self.assertEquals(self.cs.headers['User-Agent'], "custom user agent") - self.assertEquals(2, len(cl)) - CreateSend.user_agent = CreateSend.default_user_agent - - def test_clients(self): - self.cs.stub_request("clients.json", "clients.json") - cl = self.cs.clients() - self.assertEquals(2, len(cl)) - self.assertEquals("4a397ccaaa55eb4e6aa1221e1e2d7122", cl[0].ClientID) - self.assertEquals("Client One", cl[0].Name) - - def test_billing_details(self): - self.cs.stub_request("billingdetails.json", "billingdetails.json") - bd = self.cs.billing_details() - self.assertEquals(3021, bd.Credits) - - def test_countries(self): - self.cs.stub_request("countries.json", "countries.json") - countries = self.cs.countries() - self.assertEquals(245, len(countries)) - self.assertEquals("Australia", countries[11]) - - def test_systemdate(self): - self.cs.stub_request("systemdate.json", "systemdate.json") - systemdate = self.cs.systemdate() - self.assertEquals(systemdate, "2010-10-15 09:27:00") - - def test_timezones(self): - self.cs.stub_request("timezones.json", "timezones.json") - timezones = self.cs.timezones() - self.assertEquals(97, len(timezones)) - self.assertEquals("(GMT+12:00) Fiji", timezones[61]) - - def test_administrators(self): - self.cs.stub_request("admins.json", "administrators.json") - administrators = self.cs.administrators() - self.assertEquals(2, len(administrators)) - self.assertEquals('admin1@blackhole.com', administrators[0].EmailAddress) - self.assertEquals('Admin One', administrators[0].Name) - self.assertEquals('Active', administrators[0].Status) - - def test_get_primary_contact(self): - self.cs.stub_request("primarycontact.json", "admin_get_primary_contact.json") - primary_contact = self.cs.get_primary_contact() - self.assertEquals('admin@blackhole.com', primary_contact.EmailAddress) - - def test_set_primary_contact(self): - email = 'admin@blackhole.com' - self.cs.stub_request('primarycontact.json?email=%s' % quote(email, ''), 'admin_set_primary_contact.json') - result = self.cs.set_primary_contact(email) - self.assertEquals(email, result.EmailAddress) - - def test_external_session_url(self): - email = "exammple@example.com" - chrome = "None" - url = "/subscribers" - integrator_id = "qw989q8wud98qwyd" - client_id = "9q8uw9d8u9wud" - self.cs.stub_request('externalsession.json', 'external_session.json') - result = self.cs.external_session_url(email, chrome, url, integrator_id, client_id) - self.assertEquals("https://external1.createsend.com/cd/create/ABCDEF12/DEADBEEF?url=FEEDDAD1", result.SessionUrl) - - # Test fake web mode - def test_make_request_fails_when_unexpected_request_url_is_faked(self): - self.cs.stub_request("unexpected/url.json", "clients.json") - self.assertRaises(Exception, self.cs.clients) - - def test_make_request_fails_when_unexpected_request_body_is_faked(self): - c = Client() - c.stub_request("clients.json", "create_client.json", 201, "unexpected request body") - self.assertRaises(Exception, c.create, "Client Company Name", "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") - - # Test functionality of exceptions inheriting from CreateSendError - def test_bad_request(self): - c = Client() - c.stub_request("clients.json", "custom_api_error.json", 400) - try: - c.create("", "", "") - except BadRequest as br: - self.assertEquals(98798, br.data.Code) - self.assertEquals('A crazy API error', br.data.Message) - self.assertEquals('The CreateSend API responded with the following error - 98798: A crazy API error', "%s" % br) - - def test_unauthorized(self): - c = Client() - c.stub_request("clients.json", "custom_api_error.json", 401) - try: - c.create("", "", "") - except Unauthorized as ua: - self.assertEquals(98798, ua.data.Code) - self.assertEquals('A crazy API error', ua.data.Message) - self.assertEquals('The CreateSend API responded with the following error - 98798: A crazy API error', "%s" % ua) - - # Test that the corresponding exceptions are raised according to the returned http status code - def test_bad_request_on_get(self): - self.cs.stub_request('countries.json', 'custom_api_error.json', status=400) - self.assertRaises(self.error_responses[400], self.cs.countries) - - def test_unauthorized_on_get(self): - self.cs.stub_request('countries.json', 'custom_api_error.json', status=401) - self.assertRaises(self.error_responses[401], self.cs.countries) - - def test_not_found_on_get(self): - self.cs.stub_request('countries.json', None, status=404) - self.assertRaises(self.error_responses[404], self.cs.countries) - - def test_other_client_error_on_get(self): - self.cs.stub_request('countries.json', None, status=418) - self.assertRaises(self.error_responses[418], self.cs.countries) - - def test_server_error_on_get(self): - self.cs.stub_request('countries.json', None, status=500) - self.assertRaises(self.error_responses[500], self.cs.countries) - - def test_bad_request_on_post(self): - client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - client.stub_request('clients.json', 'custom_api_error.json', status=400) - self.assertRaises(self.error_responses[400], client.create, "Client Company Name", - "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") - - def test_unauthorized_on_post(self): - client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - client.stub_request('clients.json', 'custom_api_error.json', status=401) - self.assertRaises(self.error_responses[401], client.create, "Client Company Name", - "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") - - def test_not_found_on_post(self): - client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - client.stub_request('clients.json', None, status=404) - self.assertRaises(self.error_responses[404], client.create, "Client Company Name", - "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") - - def test_other_client_error_on_post(self): - client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - client.stub_request('clients.json', None, status=418) - self.assertRaises(self.error_responses[418], client.create, "Client Company Name", - "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") - - def test_server_error_on_post(self): - client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - client.stub_request('clients.json', None, status=500) - self.assertRaises(self.error_responses[500], client.create, "Client Company Name", - "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") - - def test_bad_request_on_put(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', 'custom_api_error.json', status=400) - self.assertRaises(self.error_responses[400], template.update, "Template One Updated", "http://templates.org/index.html", - "http://templates.org/files.zip") - - def test_unauthorized_on_put(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', 'custom_api_error.json', status=401) - self.assertRaises(self.error_responses[401], template.update, "Template One Updated", "http://templates.org/index.html", - "http://templates.org/files.zip") - - def test_not_found_on_put(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=404) - self.assertRaises(self.error_responses[404], template.update, "Template One Updated", "http://templates.org/index.html", - "http://templates.org/files.zip") - - def test_other_client_error_on_put(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=418) - self.assertRaises(self.error_responses[418], template.update, "Template One Updated", "http://templates.org/index.html", - "http://templates.org/files.zip") - - def test_server_error_on_put(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=500) - self.assertRaises(self.error_responses[500], template.update, "Template One Updated", "http://templates.org/index.html", - "http://templates.org/files.zip") - - def test_bad_request_on_delete(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', 'custom_api_error.json', status=400) - self.assertRaises(self.error_responses[400], template.delete) - - def test_unauthorized_on_delete(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', 'custom_api_error.json', status=401) - self.assertRaises(self.error_responses[401], template.delete) - - def test_not_found_on_delete(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=404) - self.assertRaises(self.error_responses[404], template.delete) - - def test_other_client_error_on_delete(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=418) - self.assertRaises(self.error_responses[418], template.delete) - - def test_server_error_on_delete(self): - template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") - template.stub_request('templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=500) - self.assertRaises(self.error_responses[500], template.delete) + """CreateSend tests to be run in the context of both using an API key + and using OAuth.""" + + def test_that_default_user_agent_is_set(self): + self.cs.stub_request("clients.json", "clients.json") + cl = self.cs.clients() + self.assertEquals( + self.cs.headers['User-Agent'], CreateSend.default_user_agent) + self.assertEquals(2, len(cl)) + + def test_that_custom_user_agent_can_be_set(self): + CreateSend.user_agent = "custom user agent" + self.cs.stub_request("clients.json", "clients.json") + cl = self.cs.clients() + self.assertEquals(self.cs.headers['User-Agent'], "custom user agent") + self.assertEquals(2, len(cl)) + CreateSend.user_agent = CreateSend.default_user_agent + + def test_clients(self): + self.cs.stub_request("clients.json", "clients.json") + cl = self.cs.clients() + self.assertEquals(2, len(cl)) + self.assertEquals("4a397ccaaa55eb4e6aa1221e1e2d7122", cl[0].ClientID) + self.assertEquals("Client One", cl[0].Name) + + def test_billing_details(self): + self.cs.stub_request("billingdetails.json", "billingdetails.json") + bd = self.cs.billing_details() + self.assertEquals(3021, bd.Credits) + + def test_countries(self): + self.cs.stub_request("countries.json", "countries.json") + countries = self.cs.countries() + self.assertEquals(245, len(countries)) + self.assertEquals("Australia", countries[11]) + + def test_systemdate(self): + self.cs.stub_request("systemdate.json", "systemdate.json") + systemdate = self.cs.systemdate() + self.assertEquals(systemdate, "2010-10-15 09:27:00") + + def test_timezones(self): + self.cs.stub_request("timezones.json", "timezones.json") + timezones = self.cs.timezones() + self.assertEquals(97, len(timezones)) + self.assertEquals("(GMT+12:00) Fiji", timezones[61]) + + def test_administrators(self): + self.cs.stub_request("admins.json", "administrators.json") + administrators = self.cs.administrators() + self.assertEquals(2, len(administrators)) + self.assertEquals('admin1@blackhole.com', + administrators[0].EmailAddress) + self.assertEquals('Admin One', administrators[0].Name) + self.assertEquals('Active', administrators[0].Status) + + def test_get_primary_contact(self): + self.cs.stub_request("primarycontact.json", + "admin_get_primary_contact.json") + primary_contact = self.cs.get_primary_contact() + self.assertEquals('admin@blackhole.com', primary_contact.EmailAddress) + + def test_set_primary_contact(self): + email = 'admin@blackhole.com' + self.cs.stub_request('primarycontact.json?email=%s' % + quote(email, ''), 'admin_set_primary_contact.json') + result = self.cs.set_primary_contact(email) + self.assertEquals(email, result.EmailAddress) + + def test_external_session_url(self): + email = "exammple@example.com" + chrome = "None" + url = "/subscribers" + integrator_id = "qw989q8wud98qwyd" + client_id = "9q8uw9d8u9wud" + self.cs.stub_request('externalsession.json', 'external_session.json') + result = self.cs.external_session_url( + email, chrome, url, integrator_id, client_id) + self.assertEquals( + "https://external1.createsend.com/cd/create/ABCDEF12/DEADBEEF?url=FEEDDAD1", result.SessionUrl) + + # Test fake web mode + def test_make_request_fails_when_unexpected_request_url_is_faked(self): + self.cs.stub_request("unexpected/url.json", "clients.json") + self.assertRaises(Exception, self.cs.clients) + + def test_make_request_fails_when_unexpected_request_body_is_faked(self): + c = Client() + c.stub_request("clients.json", "create_client.json", + 201, "unexpected request body") + self.assertRaises(Exception, c.create, "Client Company Name", + "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") + + # Test functionality of exceptions inheriting from CreateSendError + def test_bad_request(self): + c = Client() + c.stub_request("clients.json", "custom_api_error.json", 400) + try: + c.create("", "", "") + except BadRequest as br: + self.assertEquals(98798, br.data.Code) + self.assertEquals('A crazy API error', br.data.Message) + self.assertEquals( + 'The CreateSend API responded with the following error - 98798: A crazy API error', "%s" % br) + + def test_unauthorized(self): + c = Client() + c.stub_request("clients.json", "custom_api_error.json", 401) + try: + c.create("", "", "") + except Unauthorized as ua: + self.assertEquals(98798, ua.data.Code) + self.assertEquals('A crazy API error', ua.data.Message) + self.assertEquals( + 'The CreateSend API responded with the following error - 98798: A crazy API error', "%s" % ua) + + # Test that the corresponding exceptions are raised according to the + # returned http status code + def test_bad_request_on_get(self): + self.cs.stub_request( + 'countries.json', 'custom_api_error.json', status=400) + self.assertRaises(self.error_responses[400], self.cs.countries) + + def test_unauthorized_on_get(self): + self.cs.stub_request( + 'countries.json', 'custom_api_error.json', status=401) + self.assertRaises(self.error_responses[401], self.cs.countries) + + def test_not_found_on_get(self): + self.cs.stub_request('countries.json', None, status=404) + self.assertRaises(self.error_responses[404], self.cs.countries) + + def test_other_client_error_on_get(self): + self.cs.stub_request('countries.json', None, status=418) + self.assertRaises(self.error_responses[418], self.cs.countries) + + def test_server_error_on_get(self): + self.cs.stub_request('countries.json', None, status=500) + self.assertRaises(self.error_responses[500], self.cs.countries) + + def test_bad_request_on_post(self): + client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + client.stub_request( + 'clients.json', 'custom_api_error.json', status=400) + self.assertRaises(self.error_responses[400], client.create, "Client Company Name", + "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") + + def test_unauthorized_on_post(self): + client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + client.stub_request( + 'clients.json', 'custom_api_error.json', status=401) + self.assertRaises(self.error_responses[401], client.create, "Client Company Name", + "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") + + def test_not_found_on_post(self): + client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + client.stub_request('clients.json', None, status=404) + self.assertRaises(self.error_responses[404], client.create, "Client Company Name", + "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") + + def test_other_client_error_on_post(self): + client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + client.stub_request('clients.json', None, status=418) + self.assertRaises(self.error_responses[418], client.create, "Client Company Name", + "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") + + def test_server_error_on_post(self): + client = Client(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + client.stub_request('clients.json', None, status=500) + self.assertRaises(self.error_responses[500], client.create, "Client Company Name", + "(GMT+10:00) Canberra, Melbourne, Sydney", "Australia") + + def test_bad_request_on_put(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', 'custom_api_error.json', status=400) + self.assertRaises(self.error_responses[400], template.update, "Template One Updated", "http://templates.org/index.html", + "http://templates.org/files.zip") + + def test_unauthorized_on_put(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', 'custom_api_error.json', status=401) + self.assertRaises(self.error_responses[401], template.update, "Template One Updated", "http://templates.org/index.html", + "http://templates.org/files.zip") + + def test_not_found_on_put(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=404) + self.assertRaises(self.error_responses[404], template.update, "Template One Updated", "http://templates.org/index.html", + "http://templates.org/files.zip") + + def test_other_client_error_on_put(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=418) + self.assertRaises(self.error_responses[418], template.update, "Template One Updated", "http://templates.org/index.html", + "http://templates.org/files.zip") + + def test_server_error_on_put(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=500) + self.assertRaises(self.error_responses[500], template.update, "Template One Updated", "http://templates.org/index.html", + "http://templates.org/files.zip") + + def test_bad_request_on_delete(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', 'custom_api_error.json', status=400) + self.assertRaises(self.error_responses[400], template.delete) + + def test_unauthorized_on_delete(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', 'custom_api_error.json', status=401) + self.assertRaises(self.error_responses[401], template.delete) + + def test_not_found_on_delete(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=404) + self.assertRaises(self.error_responses[404], template.delete) + + def test_other_client_error_on_delete(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=418) + self.assertRaises(self.error_responses[418], template.delete) + + def test_server_error_on_delete(self): + template = Template(self.cs.auth_details, "uhiuhiuhiuhiuhiuhiuh") + template.stub_request( + 'templates/uhiuhiuhiuhiuhiuhiuh.json', None, status=500) + self.assertRaises(self.error_responses[500], template.delete) + class OAuthCreateSendTestCase(unittest.TestCase, CreateSendTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.cs = CreateSend({"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}) - # Mapping of http status codes to the exceptions expected to be raised - self.error_responses = { - 400: BadRequest, 401: Unauthorized, 404: NotFound, 418: ClientError, - 500: ServerError } + """Test when using OAuth to authenticate""" + + def setUp(self): + self.cs = CreateSend({"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", + "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}) + # Mapping of http status codes to the exceptions expected to be raised + self.error_responses = { + 400: BadRequest, 401: Unauthorized, 404: NotFound, 418: ClientError, + 500: ServerError} + class ApiKeyCreateSendTestCase(unittest.TestCase, CreateSendTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.cs = CreateSend({'api_key': '123123123123123123123'}) - # Mapping of http status codes to the exceptions expected to be raised - self.error_responses = { - 400: BadRequest, 401: Unauthorized, 404: NotFound, 418: ClientError, - 500: ServerError } + """Test when using an API key to authenticate""" + + def setUp(self): + self.cs = CreateSend({'api_key': '123123123123123123123'}) + # Mapping of http status codes to the exceptions expected to be raised + self.error_responses = { + 400: BadRequest, 401: Unauthorized, 404: NotFound, 418: ClientError, + 500: ServerError} diff --git a/test/test_list.py b/test/test_list.py index a86d09e..dc52723 100644 --- a/test/test_list.py +++ b/test/test_list.py @@ -1,264 +1,302 @@ -# -*- coding: utf-8 -*- - from six.moves.urllib.parse import quote import unittest -from createsend import * +from createsend.list import List + class ListTestCase(object): - def test_create_without_unsubscribe_setting(self): - l = List() - l.stub_request("lists/%s.json" % self.client_id, "create_list.json") - list_id = l.create(self.client_id, "List One", "", False, "") - self.assertEquals(list_id, "e3c5f034d68744f7881fdccf13c2daee1234") - self.assertEquals(l.list_id, "e3c5f034d68744f7881fdccf13c2daee1234") - - def test_create_with_unsubscribe_setting(self): - l = List() - l.stub_request("lists/%s.json" % self.client_id, "create_list.json") - list_id = l.create(self.client_id, "List One", "", False, "", "OnlyThisList") - self.assertEquals(list_id, "e3c5f034d68744f7881fdccf13c2daee1234") - self.assertEquals(l.list_id, "e3c5f034d68744f7881fdccf13c2daee1234") - - def test_update_without_unsubscribe_setting(self): - self.list.stub_request("lists/%s.json" % self.list.list_id, None) - self.list.update("List One Renamed", "", False, "") - - def test_update_with_unsubscribe_setting(self): - self.list.stub_request("lists/%s.json" % self.list.list_id, None) - self.list.update("List One Renamed", "", False, "", "OnlyThisList") - - def test_update_with_unsubscribe_setting_and_supp_list_options(self): - self.list.stub_request("lists/%s.json" % self.list.list_id, None) - self.list.update("List One Renamed", "", False, "", "OnlyThisList", True, True) - - def test_delete(self): - self.list.stub_request("lists/%s.json" % self.list.list_id, None) - self.list.delete() - - def test_create_custom_field(self): - self.list.stub_request("lists/%s/customfields.json" % self.list.list_id, - "create_custom_field.json", None, - "{\"DataType\": \"Date\", \"FieldName\": \"new date field\", \"Options\": [], \"VisibleInPreferenceCenter\": true}") - personalisation_tag = self.list.create_custom_field("new date field", "Date") - self.assertEquals(personalisation_tag, "[newdatefield]") - - def test_create_custom_field_with_options_and_visible_in_preference_center(self): - options = ["one", "two"] - self.list.stub_request("lists/%s/customfields.json" % self.list.list_id, - "create_custom_field.json", None, - "{\"DataType\": \"MultiSelectOne\", \"FieldName\": \"newsletter format\", \"Options\": [\"one\", \"two\"], \"VisibleInPreferenceCenter\": false}") - personalisation_tag = self.list.create_custom_field("newsletter format", - "MultiSelectOne", options, False) - self.assertEquals(personalisation_tag, "[newdatefield]") - - def test_update_custom_field(self): - key = "[mycustomfield]" - self.list.stub_request("lists/%s/customfields/%s.json" % (self.list.list_id, quote(key)), - "update_custom_field.json", None, - "{\"FieldName\": \"my renamed custom field\", \"VisibleInPreferenceCenter\": true}") - personalisation_tag = self.list.update_custom_field(key, "my renamed custom field", True) - self.assertEquals(personalisation_tag, "[myrenamedcustomfield]") - - def test_delete_custom_field(self): - custom_field_key = "[newdatefield]" - self.list.stub_request("lists/%s/customfields/%s.json" % (self.list.list_id, quote(custom_field_key)), None) - self.list.delete_custom_field(custom_field_key) - - def test_update_custom_field_options(self): - custom_field_key = "[newdatefield]" - new_options = [ "one", "two", "three" ] - self.list.stub_request("lists/%s/customfields/%s/options.json" % (self.list.list_id, quote(custom_field_key)), None) - self.list.update_custom_field_options(custom_field_key, new_options, True) - - def test_details(self): - self.list.stub_request("lists/%s.json" % self.list.list_id, "list_details.json") - details = self.list.details() - self.assertEquals(details.ConfirmedOptIn, False) - self.assertEquals(details.Title, "a non-basic list :)") - self.assertEquals(details.UnsubscribePage, "") - self.assertEquals(details.ListID, "2fe4c8f0373ce320e2200596d7ef168f") - self.assertEquals(details.ConfirmationSuccessPage, "") - - def test_custom_fields(self): - self.list.stub_request("lists/%s/customfields.json" % self.list.list_id, "custom_fields.json") - cfs = self.list.custom_fields() - self.assertEquals(len(cfs), 3) - self.assertEquals(cfs[0].FieldName, "website") - self.assertEquals(cfs[0].Key, "[website]") - self.assertEquals(cfs[0].DataType, "Text") - self.assertEquals(cfs[0].FieldOptions, []) - self.assertEquals(cfs[0].VisibleInPreferenceCenter, True) - - def test_custom_fields_utf8(self): - self.list.stub_request("lists/%s/customfields.json" % self.list.list_id, "custom_fields_utf8.json") - cfs = self.list.custom_fields() - self.assertEquals(len(cfs), 2) - self.assertEquals(cfs[0].FieldName, "salary_range") - self.assertEquals(cfs[0].FieldOptions, [u"£0-20k", u"£20-30k", u"£30k+"]) - - - def test_segments(self): - self.list.stub_request("lists/%s/segments.json" % self.list.list_id, "segments.json") - segments = self.list.segments() - self.assertEquals(len(segments), 2) - self.assertEquals(segments[0].ListID, 'a58ee1d3039b8bec838e6d1482a8a965') - self.assertEquals(segments[0].SegmentID, '46aa5e01fd43381863d4e42cf277d3a9') - self.assertEquals(segments[0].Title, 'Segment One') - - def test_stats(self): - self.list.stub_request("lists/%s/stats.json" % self.list.list_id, "list_stats.json") - stats = self.list.stats() - self.assertEquals(stats.TotalActiveSubscribers, 6) - self.assertEquals(stats.TotalUnsubscribes, 2) - self.assertEquals(stats.TotalDeleted, 0) - self.assertEquals(stats.TotalBounces, 0) - - def test_active(self): - min_date = "2010-01-01" - self.list.stub_request("lists/%s/active.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % (self.list.list_id, quote(min_date)), "active_subscribers.json") - res = self.list.active(min_date) - self.assertEquals(res.ResultsOrderedBy, "email") - self.assertEquals(res.OrderDirection, "asc") - self.assertEquals(res.PageNumber, 1) - self.assertEquals(res.PageSize, 1000) - self.assertEquals(res.RecordsOnThisPage, 5) - self.assertEquals(res.TotalNumberOfRecords, 5) - self.assertEquals(res.NumberOfPages, 1) - self.assertEquals(len(res.Results), 5) - self.assertEquals(res.Results[0].EmailAddress, "subs+7t8787Y@example.com") - self.assertEquals(res.Results[0].Name, "Person One") - self.assertEquals(res.Results[0].Date, "2010-10-25 10:28:00") - self.assertEquals(res.Results[0].State, "Active") - self.assertEquals(len(res.Results[0].CustomFields), 5) - self.assertEquals(res.Results[0].CustomFields[0].Key, "website") - self.assertEquals(res.Results[0].CustomFields[0].Value, "http://example.com") - self.assertEquals(res.Results[0].CustomFields[1].Key, "multi select field") - self.assertEquals(res.Results[0].CustomFields[1].Value, "option one") - self.assertEquals(res.Results[0].CustomFields[2].Key, "multi select field") - self.assertEquals(res.Results[0].CustomFields[2].Value, "option two") - self.assertEquals(res.Results[0].ReadsEmailWith, "Gmail") - - def test_unconfirmed(self): - min_date = "2010-01-01" - self.list.stub_request("lists/%s/unconfirmed.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % (self.list.list_id, quote(min_date)), "unconfirmed_subscribers.json") - res = self.list.unconfirmed(min_date) - self.assertEquals(res.ResultsOrderedBy, "email") - self.assertEquals(res.OrderDirection, "asc") - self.assertEquals(res.PageNumber, 1) - self.assertEquals(res.PageSize, 1000) - self.assertEquals(res.RecordsOnThisPage, 2) - self.assertEquals(res.TotalNumberOfRecords, 2) - self.assertEquals(res.NumberOfPages, 1) - self.assertEquals(len(res.Results), 2) - self.assertEquals(res.Results[0].EmailAddress, "subs+7t8787Y@example.com") - self.assertEquals(res.Results[0].Name, "Unconfirmed One") - self.assertEquals(res.Results[0].State, "Unconfirmed") - - def test_unsubscribed(self): - min_date = "2010-01-01" - self.list.stub_request("lists/%s/unsubscribed.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % (self.list.list_id, quote(min_date)), "unsubscribed_subscribers.json") - res = self.list.unsubscribed(min_date) - self.assertEquals(res.ResultsOrderedBy, "email") - self.assertEquals(res.OrderDirection, "asc") - self.assertEquals(res.PageNumber, 1) - self.assertEquals(res.PageSize, 1000) - self.assertEquals(res.RecordsOnThisPage, 5) - self.assertEquals(res.TotalNumberOfRecords, 5) - self.assertEquals(res.NumberOfPages, 1) - self.assertEquals(len(res.Results), 5) - self.assertEquals(res.Results[0].EmailAddress, "subscriber@example.com") - self.assertEquals(res.Results[0].Name, "Unsub One") - self.assertEquals(res.Results[0].Date, "2010-10-25 13:11:00") - self.assertEquals(res.Results[0].State, "Unsubscribed") - self.assertEquals(len(res.Results[0].CustomFields), 0) - self.assertEquals(res.Results[0].ReadsEmailWith, "Gmail") - - def test_deleted(self): - min_date = "2010-01-01" - self.list.stub_request("lists/%s/deleted.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % (self.list.list_id, quote(min_date)), "deleted_subscribers.json") - res = self.list.deleted(min_date) - self.assertEquals(res.ResultsOrderedBy, "email") - self.assertEquals(res.OrderDirection, "asc") - self.assertEquals(res.PageNumber, 1) - self.assertEquals(res.PageSize, 1000) - self.assertEquals(res.RecordsOnThisPage, 5) - self.assertEquals(res.TotalNumberOfRecords, 5) - self.assertEquals(res.NumberOfPages, 1) - self.assertEquals(len(res.Results), 5) - self.assertEquals(res.Results[0].EmailAddress, "subscriber@example.com") - self.assertEquals(res.Results[0].Name, "Deleted One") - self.assertEquals(res.Results[0].Date, "2010-10-25 13:11:00") - self.assertEquals(res.Results[0].State, "Deleted") - self.assertEquals(len(res.Results[0].CustomFields), 0) - self.assertEquals(res.Results[0].ReadsEmailWith, "Gmail") - - def test_bounced(self): - min_date = "2010-01-01" - self.list.stub_request("lists/%s/bounced.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % (self.list.list_id, quote(min_date)), "bounced_subscribers.json") - res = self.list.bounced(min_date) - self.assertEquals(res.ResultsOrderedBy, "email") - self.assertEquals(res.OrderDirection, "asc") - self.assertEquals(res.PageNumber, 1) - self.assertEquals(res.PageSize, 1000) - self.assertEquals(res.RecordsOnThisPage, 1) - self.assertEquals(res.TotalNumberOfRecords, 1) - self.assertEquals(res.NumberOfPages, 1) - self.assertEquals(len(res.Results), 1) - self.assertEquals(res.Results[0].EmailAddress, "bouncedsubscriber@example.com") - self.assertEquals(res.Results[0].Name, "Bounced One") - self.assertEquals(res.Results[0].Date, "2010-10-25 13:11:00") - self.assertEquals(res.Results[0].State, "Bounced") - self.assertEquals(len(res.Results[0].CustomFields), 0) - self.assertEquals(res.Results[0].ReadsEmailWith, "") - - def test_webhooks(self): - self.list.stub_request("lists/%s/webhooks.json" % self.list.list_id, "list_webhooks.json") - hooks = self.list.webhooks() - self.assertEquals(len(hooks), 2) - self.assertEquals(hooks[0].WebhookID, "943678317049bc13") - self.assertEquals(len(hooks[0].Events), 1) - self.assertEquals(hooks[0].Events[0], "Deactivate") - self.assertEquals(hooks[0].Url, "http://www.postbin.org/d9w8ud9wud9w") - self.assertEquals(hooks[0].Status, "Active") - self.assertEquals(hooks[0].PayloadFormat, "Json") - - def test_create_webhook(self): - self.list.stub_request("lists/%s/webhooks.json" % self.list.list_id, "create_list_webhook.json") - webhook_id = self.list.create_webhook(["Unsubscribe", "Spam"], "http://example.com/unsub", "json") - self.assertEquals(webhook_id, "6a783d359bd44ef62c6ca0d3eda4412a") - - def test_test_webhook(self): - webhook_id = "jiuweoiwueoiwueowiueo" - self.list.stub_request("lists/%s/webhooks/%s/test.json" % (self.list.list_id, webhook_id), None) - self.list.test_webhook(webhook_id) - - def test_delete_webhook(self): - webhook_id = "jiuweoiwueoiwueowiueo" - self.list.stub_request("lists/%s/webhooks/%s.json" % (self.list.list_id, webhook_id), None) - self.list.delete_webhook(webhook_id) - - def test_activate_webhook(self): - webhook_id = "jiuweoiwueoiwueowiueo" - self.list.stub_request("lists/%s/webhooks/%s/activate.json" % (self.list.list_id, webhook_id), None) - self.list.activate_webhook(webhook_id) - - def test_deactivate_webhook(self): - webhook_id = "jiuweoiwueoiwueowiueo" - self.list.stub_request("lists/%s/webhooks/%s/deactivate.json" % (self.list.list_id, webhook_id), None) - self.list.deactivate_webhook(webhook_id) + def test_create_without_unsubscribe_setting(self): + l = List() + l.stub_request("lists/%s.json" % self.client_id, "create_list.json") + list_id = l.create(self.client_id, "List One", "", False, "") + self.assertEquals(list_id, "e3c5f034d68744f7881fdccf13c2daee1234") + self.assertEquals(l.list_id, "e3c5f034d68744f7881fdccf13c2daee1234") + + def test_create_with_unsubscribe_setting(self): + l = List() + l.stub_request("lists/%s.json" % self.client_id, "create_list.json") + list_id = l.create(self.client_id, "List One", + "", False, "", "OnlyThisList") + self.assertEquals(list_id, "e3c5f034d68744f7881fdccf13c2daee1234") + self.assertEquals(l.list_id, "e3c5f034d68744f7881fdccf13c2daee1234") + + def test_update_without_unsubscribe_setting(self): + self.list.stub_request("lists/%s.json" % self.list.list_id, None) + self.list.update("List One Renamed", "", False, "") + + def test_update_with_unsubscribe_setting(self): + self.list.stub_request("lists/%s.json" % self.list.list_id, None) + self.list.update("List One Renamed", "", False, "", "OnlyThisList") + + def test_update_with_unsubscribe_setting_and_supp_list_options(self): + self.list.stub_request("lists/%s.json" % self.list.list_id, None) + self.list.update("List One Renamed", "", False, + "", "OnlyThisList", True, True) + + def test_delete(self): + self.list.stub_request("lists/%s.json" % self.list.list_id, None) + self.list.delete() + + def test_create_custom_field(self): + self.list.stub_request("lists/%s/customfields.json" % self.list.list_id, + "create_custom_field.json", None, + "{\"DataType\": \"Date\", \"FieldName\": \"new date field\", \"Options\": [], \"VisibleInPreferenceCenter\": true}") + personalisation_tag = self.list.create_custom_field( + "new date field", "Date") + self.assertEquals(personalisation_tag, "[newdatefield]") + + def test_create_custom_field_with_options_and_visible_in_preference_center(self): + options = ["one", "two"] + self.list.stub_request("lists/%s/customfields.json" % self.list.list_id, + "create_custom_field.json", None, + "{\"DataType\": \"MultiSelectOne\", \"FieldName\": \"newsletter format\", \"Options\": [\"one\", \"two\"], \"VisibleInPreferenceCenter\": false}") + personalisation_tag = self.list.create_custom_field("newsletter format", + "MultiSelectOne", options, False) + self.assertEquals(personalisation_tag, "[newdatefield]") + + def test_update_custom_field(self): + key = "[mycustomfield]" + self.list.stub_request("lists/%s/customfields/%s.json" % (self.list.list_id, quote(key)), + "update_custom_field.json", None, + "{\"FieldName\": \"my renamed custom field\", \"VisibleInPreferenceCenter\": true}") + personalisation_tag = self.list.update_custom_field( + key, "my renamed custom field", True) + self.assertEquals(personalisation_tag, "[myrenamedcustomfield]") + + def test_delete_custom_field(self): + custom_field_key = "[newdatefield]" + self.list.stub_request("lists/%s/customfields/%s.json" % + (self.list.list_id, quote(custom_field_key)), None) + self.list.delete_custom_field(custom_field_key) + + def test_update_custom_field_options(self): + custom_field_key = "[newdatefield]" + new_options = ["one", "two", "three"] + self.list.stub_request("lists/%s/customfields/%s/options.json" % + (self.list.list_id, quote(custom_field_key)), None) + self.list.update_custom_field_options( + custom_field_key, new_options, True) + + def test_details(self): + self.list.stub_request("lists/%s.json" % + self.list.list_id, "list_details.json") + details = self.list.details() + self.assertEquals(details.ConfirmedOptIn, False) + self.assertEquals(details.Title, "a non-basic list :)") + self.assertEquals(details.UnsubscribePage, "") + self.assertEquals(details.ListID, "2fe4c8f0373ce320e2200596d7ef168f") + self.assertEquals(details.ConfirmationSuccessPage, "") + + def test_custom_fields(self): + self.list.stub_request("lists/%s/customfields.json" % + self.list.list_id, "custom_fields.json") + cfs = self.list.custom_fields() + self.assertEquals(len(cfs), 3) + self.assertEquals(cfs[0].FieldName, "website") + self.assertEquals(cfs[0].Key, "[website]") + self.assertEquals(cfs[0].DataType, "Text") + self.assertEquals(cfs[0].FieldOptions, []) + self.assertEquals(cfs[0].VisibleInPreferenceCenter, True) + + def test_custom_fields_utf8(self): + self.list.stub_request("lists/%s/customfields.json" % + self.list.list_id, "custom_fields_utf8.json") + cfs = self.list.custom_fields() + self.assertEquals(len(cfs), 2) + self.assertEquals(cfs[0].FieldName, "salary_range") + self.assertEquals(cfs[0].FieldOptions, [ + u"£0-20k", u"£20-30k", u"£30k+"]) + + def test_segments(self): + self.list.stub_request("lists/%s/segments.json" % + self.list.list_id, "segments.json") + segments = self.list.segments() + self.assertEquals(len(segments), 2) + self.assertEquals(segments[0].ListID, + 'a58ee1d3039b8bec838e6d1482a8a965') + self.assertEquals(segments[0].SegmentID, + '46aa5e01fd43381863d4e42cf277d3a9') + self.assertEquals(segments[0].Title, 'Segment One') + + def test_stats(self): + self.list.stub_request("lists/%s/stats.json" % + self.list.list_id, "list_stats.json") + stats = self.list.stats() + self.assertEquals(stats.TotalActiveSubscribers, 6) + self.assertEquals(stats.TotalUnsubscribes, 2) + self.assertEquals(stats.TotalDeleted, 0) + self.assertEquals(stats.TotalBounces, 0) + + def test_active(self): + min_date = "2010-01-01" + self.list.stub_request("lists/%s/active.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % + (self.list.list_id, quote(min_date)), "active_subscribers.json") + res = self.list.active(min_date) + self.assertEquals(res.ResultsOrderedBy, "email") + self.assertEquals(res.OrderDirection, "asc") + self.assertEquals(res.PageNumber, 1) + self.assertEquals(res.PageSize, 1000) + self.assertEquals(res.RecordsOnThisPage, 5) + self.assertEquals(res.TotalNumberOfRecords, 5) + self.assertEquals(res.NumberOfPages, 1) + self.assertEquals(len(res.Results), 5) + self.assertEquals(res.Results[0].EmailAddress, + "subs+7t8787Y@example.com") + self.assertEquals(res.Results[0].Name, "Person One") + self.assertEquals(res.Results[0].Date, "2010-10-25 10:28:00") + self.assertEquals(res.Results[0].State, "Active") + self.assertEquals(len(res.Results[0].CustomFields), 5) + self.assertEquals(res.Results[0].CustomFields[0].Key, "website") + self.assertEquals(res.Results[0].CustomFields[ + 0].Value, "http://example.com") + self.assertEquals(res.Results[0].CustomFields[ + 1].Key, "multi select field") + self.assertEquals(res.Results[0].CustomFields[1].Value, "option one") + self.assertEquals(res.Results[0].CustomFields[ + 2].Key, "multi select field") + self.assertEquals(res.Results[0].CustomFields[2].Value, "option two") + self.assertEquals(res.Results[0].ReadsEmailWith, "Gmail") + + def test_unconfirmed(self): + min_date = "2010-01-01" + self.list.stub_request("lists/%s/unconfirmed.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % + (self.list.list_id, quote(min_date)), "unconfirmed_subscribers.json") + res = self.list.unconfirmed(min_date) + self.assertEquals(res.ResultsOrderedBy, "email") + self.assertEquals(res.OrderDirection, "asc") + self.assertEquals(res.PageNumber, 1) + self.assertEquals(res.PageSize, 1000) + self.assertEquals(res.RecordsOnThisPage, 2) + self.assertEquals(res.TotalNumberOfRecords, 2) + self.assertEquals(res.NumberOfPages, 1) + self.assertEquals(len(res.Results), 2) + self.assertEquals(res.Results[0].EmailAddress, + "subs+7t8787Y@example.com") + self.assertEquals(res.Results[0].Name, "Unconfirmed One") + self.assertEquals(res.Results[0].State, "Unconfirmed") + + def test_unsubscribed(self): + min_date = "2010-01-01" + self.list.stub_request("lists/%s/unsubscribed.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % + (self.list.list_id, quote(min_date)), "unsubscribed_subscribers.json") + res = self.list.unsubscribed(min_date) + self.assertEquals(res.ResultsOrderedBy, "email") + self.assertEquals(res.OrderDirection, "asc") + self.assertEquals(res.PageNumber, 1) + self.assertEquals(res.PageSize, 1000) + self.assertEquals(res.RecordsOnThisPage, 5) + self.assertEquals(res.TotalNumberOfRecords, 5) + self.assertEquals(res.NumberOfPages, 1) + self.assertEquals(len(res.Results), 5) + self.assertEquals( + res.Results[0].EmailAddress, "subscriber@example.com") + self.assertEquals(res.Results[0].Name, "Unsub One") + self.assertEquals(res.Results[0].Date, "2010-10-25 13:11:00") + self.assertEquals(res.Results[0].State, "Unsubscribed") + self.assertEquals(len(res.Results[0].CustomFields), 0) + self.assertEquals(res.Results[0].ReadsEmailWith, "Gmail") + + def test_deleted(self): + min_date = "2010-01-01" + self.list.stub_request("lists/%s/deleted.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % + (self.list.list_id, quote(min_date)), "deleted_subscribers.json") + res = self.list.deleted(min_date) + self.assertEquals(res.ResultsOrderedBy, "email") + self.assertEquals(res.OrderDirection, "asc") + self.assertEquals(res.PageNumber, 1) + self.assertEquals(res.PageSize, 1000) + self.assertEquals(res.RecordsOnThisPage, 5) + self.assertEquals(res.TotalNumberOfRecords, 5) + self.assertEquals(res.NumberOfPages, 1) + self.assertEquals(len(res.Results), 5) + self.assertEquals( + res.Results[0].EmailAddress, "subscriber@example.com") + self.assertEquals(res.Results[0].Name, "Deleted One") + self.assertEquals(res.Results[0].Date, "2010-10-25 13:11:00") + self.assertEquals(res.Results[0].State, "Deleted") + self.assertEquals(len(res.Results[0].CustomFields), 0) + self.assertEquals(res.Results[0].ReadsEmailWith, "Gmail") + + def test_bounced(self): + min_date = "2010-01-01" + self.list.stub_request("lists/%s/bounced.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % + (self.list.list_id, quote(min_date)), "bounced_subscribers.json") + res = self.list.bounced(min_date) + self.assertEquals(res.ResultsOrderedBy, "email") + self.assertEquals(res.OrderDirection, "asc") + self.assertEquals(res.PageNumber, 1) + self.assertEquals(res.PageSize, 1000) + self.assertEquals(res.RecordsOnThisPage, 1) + self.assertEquals(res.TotalNumberOfRecords, 1) + self.assertEquals(res.NumberOfPages, 1) + self.assertEquals(len(res.Results), 1) + self.assertEquals(res.Results[0].EmailAddress, + "bouncedsubscriber@example.com") + self.assertEquals(res.Results[0].Name, "Bounced One") + self.assertEquals(res.Results[0].Date, "2010-10-25 13:11:00") + self.assertEquals(res.Results[0].State, "Bounced") + self.assertEquals(len(res.Results[0].CustomFields), 0) + self.assertEquals(res.Results[0].ReadsEmailWith, "") + + def test_webhooks(self): + self.list.stub_request("lists/%s/webhooks.json" % + self.list.list_id, "list_webhooks.json") + hooks = self.list.webhooks() + self.assertEquals(len(hooks), 2) + self.assertEquals(hooks[0].WebhookID, "943678317049bc13") + self.assertEquals(len(hooks[0].Events), 1) + self.assertEquals(hooks[0].Events[0], "Deactivate") + self.assertEquals(hooks[0].Url, "http://www.postbin.org/d9w8ud9wud9w") + self.assertEquals(hooks[0].Status, "Active") + self.assertEquals(hooks[0].PayloadFormat, "Json") + + def test_create_webhook(self): + self.list.stub_request("lists/%s/webhooks.json" % + self.list.list_id, "create_list_webhook.json") + webhook_id = self.list.create_webhook( + ["Unsubscribe", "Spam"], "http://example.com/unsub", "json") + self.assertEquals(webhook_id, "6a783d359bd44ef62c6ca0d3eda4412a") + + def test_test_webhook(self): + webhook_id = "jiuweoiwueoiwueowiueo" + self.list.stub_request("lists/%s/webhooks/%s/test.json" % + (self.list.list_id, webhook_id), None) + self.list.test_webhook(webhook_id) + + def test_delete_webhook(self): + webhook_id = "jiuweoiwueoiwueowiueo" + self.list.stub_request("lists/%s/webhooks/%s.json" % + (self.list.list_id, webhook_id), None) + self.list.delete_webhook(webhook_id) + + def test_activate_webhook(self): + webhook_id = "jiuweoiwueoiwueowiueo" + self.list.stub_request("lists/%s/webhooks/%s/activate.json" % + (self.list.list_id, webhook_id), None) + self.list.activate_webhook(webhook_id) + + def test_deactivate_webhook(self): + webhook_id = "jiuweoiwueoiwueowiueo" + self.list.stub_request( + "lists/%s/webhooks/%s/deactivate.json" % (self.list.list_id, webhook_id), None) + self.list.deactivate_webhook(webhook_id) + class OAuthListTestCase(unittest.TestCase, ListTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.client_id = "87y8d7qyw8d7yq8w7ydwqwd" - self.list_id = "e3c5f034d68744f7881fdccf13c2daee" - self.list = List({"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, self.list_id) + """Test when using OAuth to authenticate""" + + def setUp(self): + self.client_id = "87y8d7qyw8d7yq8w7ydwqwd" + self.list_id = "e3c5f034d68744f7881fdccf13c2daee" + self.list = List({"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", + "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, self.list_id) + class ApiKeyListTestCase(unittest.TestCase, ListTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.client_id = "87y8d7qyw8d7yq8w7ydwqwd" - self.list_id = "e3c5f034d68744f7881fdccf13c2daee" - self.list = List({'api_key': '123123123123123123123'}, self.list_id) + """Test when using an API key to authenticate""" + + def setUp(self): + self.client_id = "87y8d7qyw8d7yq8w7ydwqwd" + self.list_id = "e3c5f034d68744f7881fdccf13c2daee" + self.list = List({'api_key': '123123123123123123123'}, self.list_id) diff --git a/test/test_people.py b/test/test_people.py index f4ae08d..a17fb93 100644 --- a/test/test_people.py +++ b/test/test_people.py @@ -1,55 +1,67 @@ from six.moves.urllib.parse import quote import unittest -from createsend import * +from createsend.person import Person + class PeopleTestCase(object): - def test_get(self): - email = "person@example.com" - self.person.stub_request("clients/%s/people.json?email=%s" % (self.client_id, quote(email)), "person_details.json") - person = self.person.get(self.client_id, email) - self.assertEquals(person.EmailAddress, email) - self.assertEquals(person.Name, "Person One") - self.assertEquals(person.AccessLevel, 1023) - self.assertEquals(person.Status, "Active") - - def test_get_without_args(self): - email = "person@example.com" - self.person.stub_request("clients/%s/people.json?email=%s" % (self.client_id, quote(email)), "person_details.json") - person = self.person.get() - self.assertEquals(person.EmailAddress, email) - self.assertEquals(person.Name, "Person One") - self.assertEquals(person.AccessLevel, 1023) - self.assertEquals(person.Status, "Active") - - def test_add(self): - self.person.stub_request("clients/%s/people.json" % self.client_id, "add_person.json") - result = self.person.add(self.client_id, "person@example.com", "Person Name", 1023, "Password") - self.assertEquals(result.EmailAddress, "person@example.com") - - def test_update(self): - new_email = "new_email_address@example.com" - self.person.stub_request("clients/%s/people.json?email=%s" % (self.client_id, quote(self.person.email_address)), None) - self.person.update(new_email, "Person New Name", 31, 'blah') - self.assertEquals(self.person.email_address, new_email) - - def test_delete(self): - self.person.stub_request("clients/%s/people.json?email=%s" % (self.client_id, quote(self.person.email_address)), None) - email_address = self.person.delete() + def test_get(self): + email = "person@example.com" + self.person.stub_request("clients/%s/people.json?email=%s" % + (self.client_id, quote(email)), "person_details.json") + person = self.person.get(self.client_id, email) + self.assertEquals(person.EmailAddress, email) + self.assertEquals(person.Name, "Person One") + self.assertEquals(person.AccessLevel, 1023) + self.assertEquals(person.Status, "Active") + + def test_get_without_args(self): + email = "person@example.com" + self.person.stub_request("clients/%s/people.json?email=%s" % + (self.client_id, quote(email)), "person_details.json") + person = self.person.get() + self.assertEquals(person.EmailAddress, email) + self.assertEquals(person.Name, "Person One") + self.assertEquals(person.AccessLevel, 1023) + self.assertEquals(person.Status, "Active") + + def test_add(self): + self.person.stub_request("clients/%s/people.json" % + self.client_id, "add_person.json") + result = self.person.add( + self.client_id, "person@example.com", "Person Name", 1023, "Password") + self.assertEquals(result.EmailAddress, "person@example.com") + + def test_update(self): + new_email = "new_email_address@example.com" + self.person.stub_request("clients/%s/people.json?email=%s" % + (self.client_id, quote(self.person.email_address)), None) + self.person.update(new_email, "Person New Name", 31, 'blah') + self.assertEquals(self.person.email_address, new_email) + + def test_delete(self): + self.person.stub_request("clients/%s/people.json?email=%s" % + (self.client_id, quote(self.person.email_address)), None) + email_address = self.person.delete() + class OAuthPeopleTestCase(unittest.TestCase, PeopleTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.client_id = "d98h2938d9283d982u3d98u88" - self.person = Person( - {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, - self.client_id, "person@example.com") + """Test when using OAuth to authenticate""" + + def setUp(self): + self.client_id = "d98h2938d9283d982u3d98u88" + self.person = Person( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", + "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, + self.client_id, "person@example.com") + class ApiKeyPeopleTestCase(unittest.TestCase, PeopleTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.client_id = "d98h2938d9283d982u3d98u88" - self.person = Person( - {'api_key': '123123123123123123123'}, - self.client_id, "person@example.com") + """Test when using an API key to authenticate""" + + def setUp(self): + self.client_id = "d98h2938d9283d982u3d98u88" + self.person = Person( + {'api_key': '123123123123123123123'}, + self.client_id, "person@example.com") diff --git a/test/test_segment.py b/test/test_segment.py index fc772d3..89e600b 100644 --- a/test/test_segment.py +++ b/test/test_segment.py @@ -1,77 +1,94 @@ from six.moves.urllib.parse import quote import unittest -from createsend import * +from createsend.segment import Segment + class SegmentTestCase(object): - def test_create(self): - list_id = "2983492834987394879837498" - rulegroups = [ { "Rules": [ { "RuleType": "EmailAddress", "Clause": "CONTAINS example.com" }, { "RuleType": "Name", "Clause": "EQUALS subscriber" } ] } ] - s = Segment() - s.stub_request("segments/%s.json" % list_id, "create_segment.json", None, "{\"RuleGroups\": [{\"Rules\": [{\"Clause\": \"CONTAINS example.com\", \"RuleType\": \"EmailAddress\"}, {\"Clause\": \"EQUALS subscriber\", \"RuleType\": \"Name\"}]}], \"Title\": \"new segment title\"}") - segment_id = s.create(list_id, "new segment title", rulegroups) - self.assertEquals(segment_id, "0246c2aea610a3545d9780bf6ab890061234") - self.assertEquals(s.segment_id, "0246c2aea610a3545d9780bf6ab890061234") - - def test_update(self): - rulegroups = [ { "Rules": [ { "RuleType": "Name", "Clause": "EQUALS subscriber" } ] } ] - self.segment.stub_request("segments/%s.json" % self.segment.segment_id, None, "{\"Rules\": [{\"Clause\": \"EQUALS subscriber\", \"RuleType\": \"Name\"}], \"Title\": \"new title for segment\"}") - self.segment.update("new title for segment", rulegroups) - - def test_add_rulegroup(self): - rulegroup = { "Rules": [ { "RuleType": "EmailAddress", "Clause": "CONTAINS example.com" } ] } - self.segment.stub_request("segments/%s/rules.json" % self.segment.segment_id, None, None, "{\"Rules\": [{\"Clause\": \"CONTAINS example.com\", \"RuleType\": \"EmailAddress\"}]}") - self.segment.add_rulegroup(rulegroup) - - def test_subscribers(self): - min_date = "2010-01-01" - self.segment.stub_request("segments/%s/active.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % (self.segment.segment_id, quote(min_date)), "segment_subscribers.json") - res = self.segment.subscribers(min_date) - self.assertEquals(res.ResultsOrderedBy, "email") - self.assertEquals(res.OrderDirection, "asc") - self.assertEquals(res.PageNumber, 1) - self.assertEquals(res.PageSize, 1000) - self.assertEquals(res.RecordsOnThisPage, 2) - self.assertEquals(res.TotalNumberOfRecords, 2) - self.assertEquals(res.NumberOfPages, 1) - self.assertEquals(len(res.Results), 2) - self.assertEquals(res.Results[0].EmailAddress, "personone@example.com") - self.assertEquals(res.Results[0].Name, "Person One") - self.assertEquals(res.Results[0].Date, "2010-10-27 13:13:00") - self.assertEquals(res.Results[0].State, "Active") - self.assertEquals(res.Results[0].CustomFields, []) - - def test_delete(self): - self.segment.stub_request("segments/%s.json" % self.segment.segment_id, None) - self.segment.delete() - - def test_clear_rules(self): - self.segment.stub_request("segments/%s/rules.json" % self.segment.segment_id, None) - self.segment.clear_rules() - - def test_details(self): - self.segment.stub_request("segments/%s.json" % self.segment.segment_id, "segment_details.json") - res = self.segment.details() - self.assertEquals(res.ActiveSubscribers, 0) - self.assertEquals(len(res.RuleGroups), 2) - self.assertEquals(res.RuleGroups[0].Rules[0].RuleType, "EmailAddress") - self.assertEquals(res.RuleGroups[0].Rules[0].Clause, "CONTAINS @hello.com") - self.assertEquals(res.RuleGroups[1].Rules[0].RuleType, "Name") - self.assertEquals(res.RuleGroups[1].Rules[0].Clause, "PROVIDED") - self.assertEquals(res.ListID, "2bea949d0bf96148c3e6a209d2e82060") - self.assertEquals(res.SegmentID, "dba84a225d5ce3d19105d7257baac46f") - self.assertEquals(res.Title, "My Segment") + def test_create(self): + list_id = "2983492834987394879837498" + rulegroups = [{"Rules": [{"RuleType": "EmailAddress", "Clause": "CONTAINS example.com"}, { + "RuleType": "Name", "Clause": "EQUALS subscriber"}]}] + s = Segment() + s.stub_request("segments/%s.json" % list_id, "create_segment.json", None, + "{\"RuleGroups\": [{\"Rules\": [{\"Clause\": \"CONTAINS example.com\", \"RuleType\": \"EmailAddress\"}, {\"Clause\": \"EQUALS subscriber\", \"RuleType\": \"Name\"}]}], \"Title\": \"new segment title\"}") + segment_id = s.create(list_id, "new segment title", rulegroups) + self.assertEquals(segment_id, "0246c2aea610a3545d9780bf6ab890061234") + self.assertEquals(s.segment_id, "0246c2aea610a3545d9780bf6ab890061234") + + def test_update(self): + rulegroups = [ + {"Rules": [{"RuleType": "Name", "Clause": "EQUALS subscriber"}]}] + self.segment.stub_request("segments/%s.json" % self.segment.segment_id, None, + "{\"Rules\": [{\"Clause\": \"EQUALS subscriber\", \"RuleType\": \"Name\"}], \"Title\": \"new title for segment\"}") + self.segment.update("new title for segment", rulegroups) + + def test_add_rulegroup(self): + rulegroup = { + "Rules": [{"RuleType": "EmailAddress", "Clause": "CONTAINS example.com"}]} + self.segment.stub_request("segments/%s/rules.json" % self.segment.segment_id, None, None, + "{\"Rules\": [{\"Clause\": \"CONTAINS example.com\", \"RuleType\": \"EmailAddress\"}]}") + self.segment.add_rulegroup(rulegroup) + + def test_subscribers(self): + min_date = "2010-01-01" + self.segment.stub_request("segments/%s/active.json?date=%s&orderfield=email&page=1&pagesize=1000&orderdirection=asc" % + (self.segment.segment_id, quote(min_date)), "segment_subscribers.json") + res = self.segment.subscribers(min_date) + self.assertEquals(res.ResultsOrderedBy, "email") + self.assertEquals(res.OrderDirection, "asc") + self.assertEquals(res.PageNumber, 1) + self.assertEquals(res.PageSize, 1000) + self.assertEquals(res.RecordsOnThisPage, 2) + self.assertEquals(res.TotalNumberOfRecords, 2) + self.assertEquals(res.NumberOfPages, 1) + self.assertEquals(len(res.Results), 2) + self.assertEquals(res.Results[0].EmailAddress, "personone@example.com") + self.assertEquals(res.Results[0].Name, "Person One") + self.assertEquals(res.Results[0].Date, "2010-10-27 13:13:00") + self.assertEquals(res.Results[0].State, "Active") + self.assertEquals(res.Results[0].CustomFields, []) + + def test_delete(self): + self.segment.stub_request("segments/%s.json" % + self.segment.segment_id, None) + self.segment.delete() + + def test_clear_rules(self): + self.segment.stub_request("segments/%s/rules.json" % + self.segment.segment_id, None) + self.segment.clear_rules() + + def test_details(self): + self.segment.stub_request("segments/%s.json" % + self.segment.segment_id, "segment_details.json") + res = self.segment.details() + self.assertEquals(res.ActiveSubscribers, 0) + self.assertEquals(len(res.RuleGroups), 2) + self.assertEquals(res.RuleGroups[0].Rules[0].RuleType, "EmailAddress") + self.assertEquals(res.RuleGroups[0].Rules[ + 0].Clause, "CONTAINS @hello.com") + self.assertEquals(res.RuleGroups[1].Rules[0].RuleType, "Name") + self.assertEquals(res.RuleGroups[1].Rules[0].Clause, "PROVIDED") + self.assertEquals(res.ListID, "2bea949d0bf96148c3e6a209d2e82060") + self.assertEquals(res.SegmentID, "dba84a225d5ce3d19105d7257baac46f") + self.assertEquals(res.Title, "My Segment") + class OAuthSegmentTestCase(unittest.TestCase, SegmentTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.segment_id = "98y2e98y289dh89h938389" - self.segment = Segment( - {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, self.segment_id) + """Test when using OAuth to authenticate""" + + def setUp(self): + self.segment_id = "98y2e98y289dh89h938389" + self.segment = Segment( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, self.segment_id) + class ApiKeySegmentTestCase(unittest.TestCase, SegmentTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.segment_id = "98y2e98y289dh89h938389" - self.segment = Segment({'api_key': '123123123123123123123'}, self.segment_id) + """Test when using an API key to authenticate""" + + def setUp(self): + self.segment_id = "98y2e98y289dh89h938389" + self.segment = Segment( + {'api_key': '123123123123123123123'}, self.segment_id) diff --git a/test/test_subscriber.py b/test/test_subscriber.py index 02a6f95..c0e34a9 100644 --- a/test/test_subscriber.py +++ b/test/test_subscriber.py @@ -1,172 +1,210 @@ from six.moves.urllib.parse import quote import unittest -from createsend import * +from createsend.createsend import BadRequest +from createsend.subscriber import Subscriber + class SubscriberTestCase(object): - def test_get(self): - email = "subscriber@example.com" - self.subscriber.stub_request("subscribers/%s.json?email=%s" % (self.list_id, quote(email)), "subscriber_details.json") - subscriber = self.subscriber.get(self.list_id, email) - self.assertEquals(subscriber.EmailAddress, email) - self.assertEquals(subscriber.Name, "Subscriber One") - self.assertEquals(subscriber.Date, "2010-10-25 10:28:00") - self.assertEquals(subscriber.State, "Active") - self.assertEquals(len(subscriber.CustomFields), 3) - self.assertEquals(subscriber.CustomFields[0].Key, 'website') - self.assertEquals(subscriber.CustomFields[0].Value, 'http://example.com') - self.assertEquals(subscriber.ReadsEmailWith, "Gmail") - - def test_get_without_arguments(self): - email = "subscriber@example.com" - self.subscriber.stub_request("subscribers/%s.json?email=%s" % (self.list_id, quote(email)), "subscriber_details.json") - subscriber = self.subscriber.get() - self.assertEquals(subscriber.EmailAddress, email) - self.assertEquals(subscriber.Name, "Subscriber One") - self.assertEquals(subscriber.Date, "2010-10-25 10:28:00") - self.assertEquals(subscriber.State, "Active") - self.assertEquals(len(subscriber.CustomFields), 3) - self.assertEquals(subscriber.CustomFields[0].Key, 'website') - self.assertEquals(subscriber.CustomFields[0].Value, 'http://example.com') - self.assertEquals(subscriber.ReadsEmailWith, "Gmail") - - def test_add_without_custom_fields(self): - self.subscriber.stub_request("subscribers/%s.json" % self.list_id, "add_subscriber.json") - email_address = self.subscriber.add(self.list_id, "subscriber@example.com", "Subscriber", [], True) - self.assertEquals(email_address, "subscriber@example.com") - - def test_add_with_custom_fields(self): - self.subscriber.stub_request("subscribers/%s.json" % self.list_id, "add_subscriber.json") - custom_fields = [ { "Key": 'website', "Value": 'http://example.com/' } ] - email_address = self.subscriber.add(self.list_id, "subscriber@example.com", "Subscriber", custom_fields, True) - self.assertEquals(email_address, "subscriber@example.com") - - def test_add_with_custom_fields_including_multioption(self): - self.subscriber.stub_request("subscribers/%s.json" % self.list_id, "add_subscriber.json") - custom_fields = [ { "Key": 'multioptionselectone', "Value": 'myoption' }, - { "Key": 'multioptionselectmany', "Value": 'firstoption' }, - { "Key": 'multioptionselectmany', "Value": 'secondoption' } ] - email_address = self.subscriber.add(self.list_id, "subscriber@example.com", "Subscriber", custom_fields, True) - self.assertEquals(email_address, "subscriber@example.com") - - def test_update_with_custom_fields(self): - new_email = "new_email_address@example.com" - self.subscriber.stub_request("subscribers/%s.json?email=%s" % (self.list_id, quote(self.subscriber.email_address)), None) - custom_fields = [ { "Key": 'website', "Value": 'http://example.com/' } ] - self.subscriber.update(new_email, "Subscriber", custom_fields, True) - self.assertEquals(self.subscriber.email_address, new_email) - - def test_update_with_custom_fields_including_clear_option(self): - new_email = "new_email_address@example.com" - self.subscriber.stub_request("subscribers/%s.json?email=%s" % (self.list_id, quote(self.subscriber.email_address)), None) - custom_fields = [ { "Key": 'website', "Value": 'http://example.com/', "Clear": True } ] - self.subscriber.update(new_email, "Subscriber", custom_fields, True) - self.assertEquals(self.subscriber.email_address, new_email) - - def test_import_subscribers(self): - self.subscriber.stub_request("subscribers/%s/import.json" % self.list_id, "import_subscribers.json") - subscribers = [ - { "EmailAddress": "example+1@example.com", "Name": "Example One" }, - { "EmailAddress": "example+2@example.com", "Name": "Example Two" }, - { "EmailAddress": "example+3@example.com", "Name": "Example Three" }, - ] - import_result = self.subscriber.import_subscribers(self.list_id, subscribers, True) - self.assertEquals(len(import_result.FailureDetails), 0) - self.assertEquals(import_result.TotalUniqueEmailsSubmitted, 3) - self.assertEquals(import_result.TotalExistingSubscribers, 0) - self.assertEquals(import_result.TotalNewSubscribers, 3) - self.assertEquals(len(import_result.DuplicateEmailsInSubmission), 0) - - def test_import_subscribers_start_subscription_autoresponders(self): - self.subscriber.stub_request("subscribers/%s/import.json" % self.list_id, "import_subscribers.json") - subscribers = [ - { "EmailAddress": "example+1@example.com", "Name": "Example One" }, - { "EmailAddress": "example+2@example.com", "Name": "Example Two" }, - { "EmailAddress": "example+3@example.com", "Name": "Example Three" }, - ] - import_result = self.subscriber.import_subscribers(self.list_id, subscribers, True, True) - self.assertEquals(len(import_result.FailureDetails), 0) - self.assertEquals(import_result.TotalUniqueEmailsSubmitted, 3) - self.assertEquals(import_result.TotalExistingSubscribers, 0) - self.assertEquals(import_result.TotalNewSubscribers, 3) - self.assertEquals(len(import_result.DuplicateEmailsInSubmission), 0) - - def test_import_subscribers_with_custom_fields_including_clear_option(self): - self.subscriber.stub_request("subscribers/%s/import.json" % self.list_id, "import_subscribers.json") - subscribers = [ - { "EmailAddress": "example+1@example.com", "Name": "Example One", "CustomFields": [ { "Key": "website", "Value": "", "Clear": True } ] }, - { "EmailAddress": "example+2@example.com", "Name": "Example Two", "CustomFields": [ { "Key": "website", "Value": "", "Clear": False } ] }, - { "EmailAddress": "example+3@example.com", "Name": "Example Three", "CustomFields": [ { "Key": "website", "Value": "", "Clear": False } ] }, - ] - import_result = self.subscriber.import_subscribers(self.list_id, subscribers, True) - self.assertEquals(len(import_result.FailureDetails), 0) - self.assertEquals(import_result.TotalUniqueEmailsSubmitted, 3) - self.assertEquals(import_result.TotalExistingSubscribers, 0) - self.assertEquals(import_result.TotalNewSubscribers, 3) - self.assertEquals(len(import_result.DuplicateEmailsInSubmission), 0) - - def test_import_subscribers_partial_success(self): - # Stub request with 400 Bad Request as the expected response status - self.subscriber.stub_request("subscribers/%s/import.json" % self.list_id, "import_subscribers_partial_success.json", 400) - subscribers = [ - { "EmailAddress": "example+1@example", "Name": "Example One" }, - { "EmailAddress": "example+2@example.com", "Name": "Example Two" }, - { "EmailAddress": "example+3@example.com", "Name": "Example Three" }, - ] - import_result = self.subscriber.import_subscribers(self.list_id, subscribers, True) - self.assertEquals(len(import_result.FailureDetails), 1) - self.assertEquals(import_result.FailureDetails[0].EmailAddress, "example+1@example") - self.assertEquals(import_result.FailureDetails[0].Code, 1) - self.assertEquals(import_result.FailureDetails[0].Message, "Invalid Email Address") - self.assertEquals(import_result.TotalUniqueEmailsSubmitted, 3) - self.assertEquals(import_result.TotalExistingSubscribers, 2) - self.assertEquals(import_result.TotalNewSubscribers, 0) - self.assertEquals(len(import_result.DuplicateEmailsInSubmission), 0) - - def test_import_subscribers_complete_failure_because_of_bad_request(self): - # Stub request with 400 Bad Request as the expected response status - self.subscriber.stub_request("subscribers/%s/import.json" % self.list_id, "custom_api_error.json", 400) - subscribers = [ - { "EmailAddress": "example+1@example", "Name": "Example One" }, - { "EmailAddress": "example+2@example.com", "Name": "Example Two" }, - { "EmailAddress": "example+3@example.com", "Name": "Example Three" }, - ] - self.assertRaises(BadRequest, self.subscriber.import_subscribers, self.list_id, subscribers, True) - - def test_unsubscribe(self): - self.subscriber.stub_request("subscribers/%s/unsubscribe.json" % self.list_id, None) - self.subscriber.unsubscribe() - - def test_history(self): - self.subscriber.stub_request("subscribers/%s/history.json?email=%s" % (self.list_id, quote(self.subscriber.email_address)), "subscriber_history.json") - history = self.subscriber.history() - self.assertEquals(len(history), 1) - self.assertEquals(history[0].Name, "Campaign One") - self.assertEquals(history[0].Type, "Campaign") - self.assertEquals(history[0].ID, "fc0ce7105baeaf97f47c99be31d02a91") - self.assertEquals(len(history[0].Actions), 6) - self.assertEquals(history[0].Actions[0].Event, "Open") - self.assertEquals(history[0].Actions[0].Date, "2010-10-12 13:18:00") - self.assertEquals(history[0].Actions[0].IPAddress, "192.168.126.87") - self.assertEquals(history[0].Actions[0].Detail, "") - - def test_delete(self): - self.subscriber.stub_request("subscribers/%s.json?email=%s" % (self.list_id, quote(self.subscriber.email_address)), None) - self.subscriber.delete() + def test_get(self): + email = "subscriber@example.com" + self.subscriber.stub_request("subscribers/%s.json?email=%s" % + (self.list_id, quote(email)), "subscriber_details.json") + subscriber = self.subscriber.get(self.list_id, email) + self.assertEquals(subscriber.EmailAddress, email) + self.assertEquals(subscriber.Name, "Subscriber One") + self.assertEquals(subscriber.Date, "2010-10-25 10:28:00") + self.assertEquals(subscriber.State, "Active") + self.assertEquals(len(subscriber.CustomFields), 3) + self.assertEquals(subscriber.CustomFields[0].Key, 'website') + self.assertEquals(subscriber.CustomFields[ + 0].Value, 'http://example.com') + self.assertEquals(subscriber.ReadsEmailWith, "Gmail") + + def test_get_without_arguments(self): + email = "subscriber@example.com" + self.subscriber.stub_request("subscribers/%s.json?email=%s" % + (self.list_id, quote(email)), "subscriber_details.json") + subscriber = self.subscriber.get() + self.assertEquals(subscriber.EmailAddress, email) + self.assertEquals(subscriber.Name, "Subscriber One") + self.assertEquals(subscriber.Date, "2010-10-25 10:28:00") + self.assertEquals(subscriber.State, "Active") + self.assertEquals(len(subscriber.CustomFields), 3) + self.assertEquals(subscriber.CustomFields[0].Key, 'website') + self.assertEquals(subscriber.CustomFields[ + 0].Value, 'http://example.com') + self.assertEquals(subscriber.ReadsEmailWith, "Gmail") + + def test_add_without_custom_fields(self): + self.subscriber.stub_request( + "subscribers/%s.json" % self.list_id, "add_subscriber.json") + email_address = self.subscriber.add( + self.list_id, "subscriber@example.com", "Subscriber", [], True) + self.assertEquals(email_address, "subscriber@example.com") + + def test_add_with_custom_fields(self): + self.subscriber.stub_request( + "subscribers/%s.json" % self.list_id, "add_subscriber.json") + custom_fields = [{"Key": 'website', "Value": 'http://example.com/'}] + email_address = self.subscriber.add( + self.list_id, "subscriber@example.com", "Subscriber", custom_fields, True) + self.assertEquals(email_address, "subscriber@example.com") + + def test_add_with_custom_fields_including_multioption(self): + self.subscriber.stub_request( + "subscribers/%s.json" % self.list_id, "add_subscriber.json") + custom_fields = [{"Key": 'multioptionselectone', "Value": 'myoption'}, + {"Key": 'multioptionselectmany', "Value": 'firstoption'}, + {"Key": 'multioptionselectmany', "Value": 'secondoption'}] + email_address = self.subscriber.add( + self.list_id, "subscriber@example.com", "Subscriber", custom_fields, True) + self.assertEquals(email_address, "subscriber@example.com") + + def test_update_with_custom_fields(self): + new_email = "new_email_address@example.com" + self.subscriber.stub_request("subscribers/%s.json?email=%s" % + (self.list_id, quote(self.subscriber.email_address)), None) + custom_fields = [{"Key": 'website', "Value": 'http://example.com/'}] + self.subscriber.update(new_email, "Subscriber", custom_fields, True) + self.assertEquals(self.subscriber.email_address, new_email) + + def test_update_with_custom_fields_including_clear_option(self): + new_email = "new_email_address@example.com" + self.subscriber.stub_request("subscribers/%s.json?email=%s" % + (self.list_id, quote(self.subscriber.email_address)), None) + custom_fields = [ + {"Key": 'website', "Value": 'http://example.com/', "Clear": True}] + self.subscriber.update(new_email, "Subscriber", custom_fields, True) + self.assertEquals(self.subscriber.email_address, new_email) + + def test_import_subscribers(self): + self.subscriber.stub_request( + "subscribers/%s/import.json" % self.list_id, "import_subscribers.json") + subscribers = [ + {"EmailAddress": "example+1@example.com", "Name": "Example One"}, + {"EmailAddress": "example+2@example.com", "Name": "Example Two"}, + {"EmailAddress": "example+3@example.com", "Name": "Example Three"}, + ] + import_result = self.subscriber.import_subscribers( + self.list_id, subscribers, True) + self.assertEquals(len(import_result.FailureDetails), 0) + self.assertEquals(import_result.TotalUniqueEmailsSubmitted, 3) + self.assertEquals(import_result.TotalExistingSubscribers, 0) + self.assertEquals(import_result.TotalNewSubscribers, 3) + self.assertEquals(len(import_result.DuplicateEmailsInSubmission), 0) + + def test_import_subscribers_start_subscription_autoresponders(self): + self.subscriber.stub_request( + "subscribers/%s/import.json" % self.list_id, "import_subscribers.json") + subscribers = [ + {"EmailAddress": "example+1@example.com", "Name": "Example One"}, + {"EmailAddress": "example+2@example.com", "Name": "Example Two"}, + {"EmailAddress": "example+3@example.com", "Name": "Example Three"}, + ] + import_result = self.subscriber.import_subscribers( + self.list_id, subscribers, True, True) + self.assertEquals(len(import_result.FailureDetails), 0) + self.assertEquals(import_result.TotalUniqueEmailsSubmitted, 3) + self.assertEquals(import_result.TotalExistingSubscribers, 0) + self.assertEquals(import_result.TotalNewSubscribers, 3) + self.assertEquals(len(import_result.DuplicateEmailsInSubmission), 0) + + def test_import_subscribers_with_custom_fields_including_clear_option(self): + self.subscriber.stub_request( + "subscribers/%s/import.json" % self.list_id, "import_subscribers.json") + subscribers = [ + {"EmailAddress": "example+1@example.com", "Name": "Example One", + "CustomFields": [{"Key": "website", "Value": "", "Clear": True}]}, + {"EmailAddress": "example+2@example.com", "Name": "Example Two", + "CustomFields": [{"Key": "website", "Value": "", "Clear": False}]}, + {"EmailAddress": "example+3@example.com", "Name": "Example Three", + "CustomFields": [{"Key": "website", "Value": "", "Clear": False}]}, + ] + import_result = self.subscriber.import_subscribers( + self.list_id, subscribers, True) + self.assertEquals(len(import_result.FailureDetails), 0) + self.assertEquals(import_result.TotalUniqueEmailsSubmitted, 3) + self.assertEquals(import_result.TotalExistingSubscribers, 0) + self.assertEquals(import_result.TotalNewSubscribers, 3) + self.assertEquals(len(import_result.DuplicateEmailsInSubmission), 0) + + def test_import_subscribers_partial_success(self): + # Stub request with 400 Bad Request as the expected response status + self.subscriber.stub_request("subscribers/%s/import.json" % + self.list_id, "import_subscribers_partial_success.json", 400) + subscribers = [ + {"EmailAddress": "example+1@example", "Name": "Example One"}, + {"EmailAddress": "example+2@example.com", "Name": "Example Two"}, + {"EmailAddress": "example+3@example.com", "Name": "Example Three"}, + ] + import_result = self.subscriber.import_subscribers( + self.list_id, subscribers, True) + self.assertEquals(len(import_result.FailureDetails), 1) + self.assertEquals(import_result.FailureDetails[ + 0].EmailAddress, "example+1@example") + self.assertEquals(import_result.FailureDetails[0].Code, 1) + self.assertEquals(import_result.FailureDetails[ + 0].Message, "Invalid Email Address") + self.assertEquals(import_result.TotalUniqueEmailsSubmitted, 3) + self.assertEquals(import_result.TotalExistingSubscribers, 2) + self.assertEquals(import_result.TotalNewSubscribers, 0) + self.assertEquals(len(import_result.DuplicateEmailsInSubmission), 0) + + def test_import_subscribers_complete_failure_because_of_bad_request(self): + # Stub request with 400 Bad Request as the expected response status + self.subscriber.stub_request( + "subscribers/%s/import.json" % self.list_id, "custom_api_error.json", 400) + subscribers = [ + {"EmailAddress": "example+1@example", "Name": "Example One"}, + {"EmailAddress": "example+2@example.com", "Name": "Example Two"}, + {"EmailAddress": "example+3@example.com", "Name": "Example Three"}, + ] + self.assertRaises( + BadRequest, self.subscriber.import_subscribers, self.list_id, subscribers, True) + + def test_unsubscribe(self): + self.subscriber.stub_request( + "subscribers/%s/unsubscribe.json" % self.list_id, None) + self.subscriber.unsubscribe() + + def test_history(self): + self.subscriber.stub_request("subscribers/%s/history.json?email=%s" % ( + self.list_id, quote(self.subscriber.email_address)), "subscriber_history.json") + history = self.subscriber.history() + self.assertEquals(len(history), 1) + self.assertEquals(history[0].Name, "Campaign One") + self.assertEquals(history[0].Type, "Campaign") + self.assertEquals(history[0].ID, "fc0ce7105baeaf97f47c99be31d02a91") + self.assertEquals(len(history[0].Actions), 6) + self.assertEquals(history[0].Actions[0].Event, "Open") + self.assertEquals(history[0].Actions[0].Date, "2010-10-12 13:18:00") + self.assertEquals(history[0].Actions[0].IPAddress, "192.168.126.87") + self.assertEquals(history[0].Actions[0].Detail, "") + + def test_delete(self): + self.subscriber.stub_request("subscribers/%s.json?email=%s" % + (self.list_id, quote(self.subscriber.email_address)), None) + self.subscriber.delete() + class OAuthSubscriberTestCase(unittest.TestCase, SubscriberTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.list_id = "d98h2938d9283d982u3d98u88" - self.subscriber = Subscriber( - {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, - self.list_id, "subscriber@example.com") + """Test when using OAuth to authenticate""" + + def setUp(self): + self.list_id = "d98h2938d9283d982u3d98u88" + self.subscriber = Subscriber( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", + "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, + self.list_id, "subscriber@example.com") + class ApiKeySubscriberTestCase(unittest.TestCase, SubscriberTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.list_id = "d98h2938d9283d982u3d98u88" - self.subscriber = Subscriber( - {'api_key': '123123123123123123123'}, - self.list_id, "subscriber@example.com") + """Test when using an API key to authenticate""" + + def setUp(self): + self.list_id = "d98h2938d9283d982u3d98u88" + self.subscriber = Subscriber( + {'api_key': '123123123123123123123'}, + self.list_id, "subscriber@example.com") diff --git a/test/test_template.py b/test/test_template.py index 334977d..40faa5c 100644 --- a/test/test_template.py +++ b/test/test_template.py @@ -1,45 +1,56 @@ import unittest -import urllib -from createsend import * +from createsend.template import Template + class TemplateTestCase(object): - def test_create(self): - client_id = '87y8d7qyw8d7yq8w7ydwqwd' - t = Template() - t.stub_request("templates/%s.json" % client_id, "create_template.json") - template_id = t.create(client_id, "Template One", "http://templates.org/index.html", - "http://templates.org/files.zip") - self.assertEquals(template_id, "98y2e98y289dh89h9383891234") - self.assertEquals(t.template_id, "98y2e98y289dh89h9383891234") - - def test_details(self): - self.template.stub_request("templates/%s.json" % self.template.template_id, "template_details.json") - t = self.template.details() - self.assertEquals(t.TemplateID, "98y2e98y289dh89h938389") - self.assertEquals(t.Name, "Template One") - self.assertEquals(t.PreviewURL, "http://preview.createsend.com/createsend/templates/previewTemplate.aspx?ID=01AF532CD8889B33&d=r&c=E816F55BFAD1A753") - self.assertEquals(t.ScreenshotURL, "http://preview.createsend.com/ts/r/14/833/263/14833263.jpg?0318092600") - - def test_update(self): - self.template.stub_request("templates/%s.json" % self.template.template_id, None) - self.template.update("Template One Updated", "http://templates.org/index.html", "http://templates.org/files.zip") - - def test_delete(self): - self.template.stub_request("templates/%s.json" % self.template.template_id, None) - self.template.delete() + def test_create(self): + client_id = '87y8d7qyw8d7yq8w7ydwqwd' + t = Template() + t.stub_request("templates/%s.json" % client_id, "create_template.json") + template_id = t.create(client_id, "Template One", "http://templates.org/index.html", + "http://templates.org/files.zip") + self.assertEquals(template_id, "98y2e98y289dh89h9383891234") + self.assertEquals(t.template_id, "98y2e98y289dh89h9383891234") + + def test_details(self): + self.template.stub_request( + "templates/%s.json" % self.template.template_id, "template_details.json") + t = self.template.details() + self.assertEquals(t.TemplateID, "98y2e98y289dh89h938389") + self.assertEquals(t.Name, "Template One") + self.assertEquals( + t.PreviewURL, "http://preview.createsend.com/createsend/templates/previewTemplate.aspx?ID=01AF532CD8889B33&d=r&c=E816F55BFAD1A753") + self.assertEquals( + t.ScreenshotURL, "http://preview.createsend.com/ts/r/14/833/263/14833263.jpg?0318092600") + + def test_update(self): + self.template.stub_request("templates/%s.json" % + self.template.template_id, None) + self.template.update( + "Template One Updated", "http://templates.org/index.html", "http://templates.org/files.zip") + + def test_delete(self): + self.template.stub_request("templates/%s.json" % + self.template.template_id, None) + self.template.delete() + class OAuthTemplateTestCase(unittest.TestCase, TemplateTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.template = Template( - {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, - "98y2e98y289dh89h938389") + """Test when using OAuth to authenticate""" + + def setUp(self): + self.template = Template( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", + "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, + "98y2e98y289dh89h938389") + class ApiKeyTemplateTestCase(unittest.TestCase, TemplateTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.template = Template( - {'api_key': '123123123123123123123'}, - "98y2e98y289dh89h938389") + """Test when using an API key to authenticate""" + + def setUp(self): + self.template = Template( + {'api_key': '123123123123123123123'}, + "98y2e98y289dh89h938389") diff --git a/test/test_transactional.py b/test/test_transactional.py index 8042f3a..2d63419 100644 --- a/test/test_transactional.py +++ b/test/test_transactional.py @@ -1,66 +1,82 @@ import unittest -import urllib -from createsend import * +from createsend.transactional import Transactional + class TransactionalTestCase(object): def test_smart_email_list(self): status = "all" - self.tx.stub_request("transactional/smartEmail?status=%s" % status, "tx_smartemails.json") + self.tx.stub_request("transactional/smartEmail?status=%s" % + status, "tx_smartemails.json") list = self.tx.smart_email_list(status) self.assertEqual(list[0].Name, "Welcome email") def test_active_smart_email_list(self): - self.tx.stub_request("transactional/smartEmail?status=active", "tx_smartemails.json") + self.tx.stub_request( + "transactional/smartEmail?status=active", "tx_smartemails.json") list = self.tx.smart_email_list(status="active") self.assertEqual(list[0].Status, "Active") def test_smart_email_list_with_client(self): - self.tx.stub_request("transactional/smartEmail?status=all&clientID=%s" % self.client_id, "tx_smartemails.json") + self.tx.stub_request("transactional/smartEmail?status=all&clientID=%s" % + self.client_id, "tx_smartemails.json") list = self.tx.smart_email_list(client_id=self.client_id) self.assertEqual(list[0].Name, "Welcome email") def test_smart_email_details(self): - self.tx.stub_request("transactional/smartEmail/%s" % self.smart_email_id, "tx_smartemail_details.json") + self.tx.stub_request("transactional/smartEmail/%s" % + self.smart_email_id, "tx_smartemail_details.json") email = self.tx.smart_email_details(self.smart_email_id) self.assertEqual(email.Name, "Reset Password") def test_smart_email_send_single(self): - self.tx.stub_request("transactional/smartEmail/%s/send" % self.smart_email_id, "tx_send_single.json") - send = self.tx.smart_email_send(self.smart_email_id, "\"Bob Sacamano\" ") + self.tx.stub_request("transactional/smartEmail/%s/send" % + self.smart_email_id, "tx_send_single.json") + send = self.tx.smart_email_send( + self.smart_email_id, "\"Bob Sacamano\" ") self.assertEqual(send[0].Status, "Received") def test_smart_email_send_multiple(self): - self.tx.stub_request("transactional/smartEmail/%s/send" % self.smart_email_id, "tx_send_multiple.json") - send = self.tx.smart_email_send(self.smart_email_id, ["\"Bob Sacamano\" ", "\"Newman\" "]) + self.tx.stub_request("transactional/smartEmail/%s/send" % + self.smart_email_id, "tx_send_multiple.json") + send = self.tx.smart_email_send(self.smart_email_id, [ + "\"Bob Sacamano\" ", "\"Newman\" "]) self.assertEqual(send[1].Recipient, "\"Newman\" ") def test_classic_email_send(self): - self.tx.stub_request("transactional/classicEmail/send", "tx_send_single.json") - send = self.tx.classic_email_send("This is the subject", "from@example.com", "\"Bob Sacamano\" ") - self.assertEqual(send[0].Recipient, "\"Bob Sacamano\" ") + self.tx.stub_request( + "transactional/classicEmail/send", "tx_send_single.json") + send = self.tx.classic_email_send( + "This is the subject", "from@example.com", "\"Bob Sacamano\" ") + self.assertEqual(send[0].Recipient, + "\"Bob Sacamano\" ") def test_classic_email_groups(self): - self.tx.stub_request("transactional/classicEmail/groups", "tx_classicemail_groups.json") + self.tx.stub_request( + "transactional/classicEmail/groups", "tx_classicemail_groups.json") groups = self.tx.classic_email_groups() self.assertEqual(groups[0].Group, "Password Reset") def test_classic_email_groups_with_client(self): - self.tx.stub_request("transactional/classicEmail/groups?clientID=%s" % self.client_id, "tx_classicemail_groups.json") + self.tx.stub_request("transactional/classicEmail/groups?clientID=%s" % + self.client_id, "tx_classicemail_groups.json") groups = self.tx.classic_email_groups(client_id=self.client_id) self.assertEqual(groups[0].Group, "Password Reset") def test_statistics(self): - self.tx.stub_request("transactional/statistics", "tx_statistics_classic.json") + self.tx.stub_request("transactional/statistics", + "tx_statistics_classic.json") stats = self.tx.statistics() self.assertEqual(stats.Query.Group, "Password Reset") def test_statistics_with_options(self): start = "2014-02-03" end = "2015-02-02" - self.tx.stub_request('transactional/statistics?to=%s&from=%s&clientID=%s' % (end, start, self.client_id), "tx_statistics_classic.json") - stats = self.tx.statistics({'clientID': self.client_id, 'from': start, 'to': end}) + self.tx.stub_request('transactional/statistics?to=%s&from=%s&clientID=%s' % + (end, start, self.client_id), "tx_statistics_classic.json") + stats = self.tx.statistics( + {'clientID': self.client_id, 'from': start, 'to': end}) self.assertEqual(stats.Query.Group, "Password Reset") def test_timeline(self): @@ -70,51 +86,60 @@ def test_timeline(self): self.assertEqual(timeline[0].Status, "Delivered") def test_timeline_classic_with_options(self): - self.tx.stub_request('transactional/messages?status=%s&group=%s' % ("all", "Password+Reset"), "tx_messages_classic.json") - timeline = self.tx.message_timeline({'status':'all','group':'Password Reset'}) + self.tx.stub_request('transactional/messages?status=%s&group=%s' % + ("all", "Password+Reset"), "tx_messages_classic.json") + timeline = self.tx.message_timeline( + {'status': 'all', 'group': 'Password Reset'}) self.assertEqual(timeline[0].Group, "Password Reset") def test_timeline_smart_with_options(self): - self.tx.stub_request('transactional/messages?status=%s&smartEmailID=%s' % ("all", self.smart_email_id), "tx_messages_smart.json") - timeline = self.tx.message_timeline({'status':'all','smartEmailID':self.smart_email_id}) + self.tx.stub_request('transactional/messages?status=%s&smartEmailID=%s' % + ("all", self.smart_email_id), "tx_messages_smart.json") + timeline = self.tx.message_timeline( + {'status': 'all', 'smartEmailID': self.smart_email_id}) self.assertEqual(timeline[0].SmartEmailID, self.smart_email_id) def test_message_details(self): - self.tx.stub_request('transactional/messages/%s?statistics=False' % (self.message_id), "tx_message_details.json") + self.tx.stub_request('transactional/messages/%s?statistics=False' % + (self.message_id), "tx_message_details.json") msg = self.tx.message_details(self.message_id, statistics=False) self.assertEqual(msg.MessageID, self.message_id) def test_message_details_with_stats(self): - self.tx.stub_request('transactional/messages/%s?statistics=True' % (self.message_id), "tx_message_details_with_statistics.json") + self.tx.stub_request('transactional/messages/%s?statistics=True' % + (self.message_id), "tx_message_details_with_statistics.json") msg = self.tx.message_details(self.message_id, statistics=True) self.assertEqual(len(msg.Opens), 1) self.assertEqual(len(msg.Clicks), 1) def test_message_resend(self): - self.tx.stub_request('transactional/messages/%s/resend' % (self.message_id), "tx_send_single.json") + self.tx.stub_request('transactional/messages/%s/resend' % + (self.message_id), "tx_send_single.json") send = self.tx.message_resend(self.message_id) self.assertEqual(send[0].Status, "Received") class OAuthTransactionalTestCase(unittest.TestCase, TransactionalTestCase): - """Test when using OAuth to authenticate""" - def setUp(self): - self.client_id = '87y8d7qyw8d7yq8w7ydwqwd' - self.smart_email_id = '21dab350-f484-11e4-ad38-6c4008bc7468' - self.message_id = 'ddc697c7-0788-4df3-a71a-a7cb935f00bd' - self.before_id = 'e2e270e6-fbce-11e4-97fc-a7cf717ca157' - self.after_id = 'e96fc6ca-fbce-11e4-949f-c3ccd6a68863' - self.tx = Transactional( - {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, "admin@example.com") + """Test when using OAuth to authenticate""" -class ApiKeyTransactionalTestCase(unittest.TestCase, TransactionalTestCase): - """Test when using an API key to authenticate""" - def setUp(self): - self.client_id = '87y8d7qyw8d7yq8w7ydwqwd' - self.smart_email_id = '21dab350-f484-11e4-ad38-6c4008bc7468' - self.message_id = 'ddc697c7-0788-4df3-a71a-a7cb935f00bd' - self.before_id = 'e2e270e6-fbce-11e4-97fc-a7cf717ca157' - self.after_id = 'e96fc6ca-fbce-11e4-949f-c3ccd6a68863' - self.tx = Transactional( - {'api_key': '123123123123123123123'}, "admin@example.com") + def setUp(self): + self.client_id = '87y8d7qyw8d7yq8w7ydwqwd' + self.smart_email_id = '21dab350-f484-11e4-ad38-6c4008bc7468' + self.message_id = 'ddc697c7-0788-4df3-a71a-a7cb935f00bd' + self.before_id = 'e2e270e6-fbce-11e4-97fc-a7cf717ca157' + self.after_id = 'e96fc6ca-fbce-11e4-949f-c3ccd6a68863' + self.tx = Transactional( + {"access_token": "ASP95S4aR+9KsgfHB0dapTYxNA==", "refresh_token": "5S4aASP9R+9KsgfHB0dapTYxNA=="}, "admin@example.com") + +class ApiKeyTransactionalTestCase(unittest.TestCase, TransactionalTestCase): + """Test when using an API key to authenticate""" + + def setUp(self): + self.client_id = '87y8d7qyw8d7yq8w7ydwqwd' + self.smart_email_id = '21dab350-f484-11e4-ad38-6c4008bc7468' + self.message_id = 'ddc697c7-0788-4df3-a71a-a7cb935f00bd' + self.before_id = 'e2e270e6-fbce-11e4-97fc-a7cf717ca157' + self.after_id = 'e96fc6ca-fbce-11e4-949f-c3ccd6a68863' + self.tx = Transactional( + {'api_key': '123123123123123123123'}, "admin@example.com") diff --git a/test/test_verifiedhttpsconnection.py b/test/test_verifiedhttpsconnection.py index f1af94d..6847b5e 100644 --- a/test/test_verifiedhttpsconnection.py +++ b/test/test_verifiedhttpsconnection.py @@ -1,16 +1,18 @@ import unittest -from createsend import * +from createsend.createsend import CreateSend, Unauthorized from createsend.utils import match_hostname + class VerifiedHTTPSConnectionTestCase(unittest.TestCase): - def setUp(self): - self.cs = CreateSend({'api_key': 'not an api key'}) + def setUp(self): + self.cs = CreateSend({'api_key': 'not an api key'}) - def test_verified_connection_no_cert(self): - self.assertRaises(ValueError, match_hostname, None, 'api.createsend.com') + def test_verified_connection_no_cert(self): + self.assertRaises(ValueError, match_hostname, + None, 'api.createsend.com') - def test_verified_connection(self): - # An actual (non-stubbed) unauthenticated request to test verification. - self.assertRaises(Unauthorized, self.cs.clients) + def test_verified_connection(self): + # An actual (non-stubbed) unauthenticated request to test verification. + self.assertRaises(Unauthorized, self.cs.clients)