Skip to content
This repository was archived by the owner on Aug 29, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aweber_api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from urlparse import parse_qs
from urllib.parse import parse_qs

from aweber_api.base import (
ACCESS_TOKEN_URL,
Expand Down
173 changes: 173 additions & 0 deletions aweber_api/__init__.py.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
from urlparse import parse_qs

from aweber_api.base import (
ACCESS_TOKEN_URL,
APIException,
API_BASE,
AUTHORIZE_URL,
AWeberBase,
REQUEST_TOKEN_URL,
)
from aweber_api.collection import AWeberCollection
from aweber_api.entry import AWeberEntry
from aweber_api.oauth import OAuthAdapter
from aweber_api.response import AWeberResponse


class AWeberAPI(AWeberBase):
"""Base class for connecting to the AWeberAPI.

Created with a consumer key and secret, then used to either generate
tokens for authorizing a user, or can be provided tokens and used to
access that user's resources.

"""

def __init__(self, consumer_key, consumer_secret):
self.adapter = OAuthAdapter(consumer_key, consumer_secret, API_BASE)
self.adapter.user = AWeberUser()

@classmethod
def parse_authorization_code(cls, authorization_code):
"""Exchange an authorization code for new api keys.

Returns a tuple containing the new consumer key/secret and
access token key/secret.

"""
# parse and validate authorization code
keys = cls._parse_and_validate_authorization_code(authorization_code)
consumer_key = keys[0]
consumer_secret = keys[1]

# create an instance of AWeberAPI for getting the access token
instance = cls._create_new_instance(keys)

# exchange request token for an access token
access_key, access_secret = instance.get_access_token()

# return consumer key/secret and access token key/secret
return consumer_key, consumer_secret, access_key, access_secret

@classmethod
def _parse_and_validate_authorization_code(cls, authorization_code):
"""parse and validate authorization code."""
keys = authorization_code.split('|')
if len(keys) < 5:
raise APIException('Invalid Authorization Code')

return keys

@classmethod
def _create_new_instance(cls, keys):
"""Create an instance of AWeberAPI for getting the access token."""
instance = cls(keys[0], keys[1])
instance.user.request_token = keys[2]
instance.user.token_secret = keys[3]
instance.user.verifier = keys[4]

return instance

@property
def authorize_url(self):
"""Return the authorize url.

Potentially containing the request token parameter.

"""
if self.user.request_token:
return "{0}?oauth_token={1}".format(
AUTHORIZE_URL, self.user.request_token)

return AUTHORIZE_URL

def get_request_token(self, callback_url):
"""Get a new request token / token secret for the callback url.

Returns request token / secret, and sets properties on the
AWeberUser object (self.user).

"""
data = {'oauth_callback': callback_url}
response = self.adapter.request(
'POST', REQUEST_TOKEN_URL, data)
self.user.request_token, self.user.token_secret = (
self._parse_token_response(response))

return (self.user.request_token, self.user.token_secret)

def get_access_token(self):
"""Exchange request tokens for Access tokens.

Gets an access token for the combination of
* request token
* token secret
* verifier
in the AWeberUser object at self.user.

Updates the user object and returns the tokens.

"""
data = {'oauth_verifier': self.user.verifier}
response = self.adapter.request(
'POST', ACCESS_TOKEN_URL, data)
self.user.access_token, self.user.token_secret = (
self._parse_token_response(response))

return (self.user.access_token, self.user.token_secret)

def _parse_token_response(self, response):
"""Parses token response.

Return the token key and the token secret

"""
if not isinstance(response, str):
raise TypeError('Expected response to be a string')

data = parse_qs(response)

if (data.get('oauth_token') is None) or (
data.get('oauth_token_secret') is None):
raise ValueError('OAuth parameters not returned')

return (data['oauth_token'][0], data['oauth_token_secret'][0])

def get_account(self, access_token=False, token_secret=False):
"""Returns the AWeberEntry object for the account.

Specified by the access_token and token_secret currently
in the self.user object.

Optionally, access_token and token_secret can be provided to
replace the properties in self.user.access_token and
self.user.token_secret, respectively.

"""
if access_token:
self.user.access_token = access_token
if token_secret:
self.user.token_secret = token_secret

url = '/accounts'
response = self.adapter.request('GET', url)
accounts = self._read_response(url, response)

return accounts[0]


class AWeberUser(object):
"""Data storage object representing the user in the OAuth model.

Has properties for request_token, token_secret, access_token, and
verifier.

"""
request_token = None
token_secret = None
access_token = None
verifier = None

def get_highest_priority_token(self):
"""Return either the access token or the request token."""
return self.access_token or self.request_token
6 changes: 3 additions & 3 deletions aweber_api/collection.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from math import floor
from urlparse import parse_qs
from urllib import urlencode
from urllib.parse import parse_qs
from urllib.parse import urlencode

from aweber_api.base import API_BASE
from aweber_api.entry import AWeberEntry
Expand Down Expand Up @@ -122,7 +122,7 @@ def __len__(self):
def __iter__(self):
return self

def next(self):
def __next__(self):
"""Get the next entry in the collection."""
if self._current < self.total_size:
self._current += 1
Expand Down
141 changes: 141 additions & 0 deletions aweber_api/collection.py.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
from math import floor
from urlparse import parse_qs
from urllib import urlencode

from aweber_api.base import API_BASE
from aweber_api.entry import AWeberEntry
from aweber_api.response import AWeberResponse


class AWeberCollection(AWeberResponse):
"""Represents a collection of similar objects.

Encapsulates data that is found at the base URI's for a given object
type, ie:
/accounts
/accounts/XXX/lists

Parses the data from the response and provides basic sequence like
operations, such as iteration and indexing to access the entries
that are contained in this collection.

"""

page_size = 100

def __init__(self, url, data, adapter):
self._entry_data = {}
self._current = 0

super(AWeberCollection, self).__init__(url, data, adapter)
self._key_entries(self._data)

def get_by_id(self, id):
"""Returns an entry from this collection.

The Entry as found by its actual AWeber id, not its offset.
Will actually request the data from the API.

"""
return self.load_from_url("{0}/{1}".format(self.url, id))

def _key_entries(self, response):
count = 0
for entry in response['entries']:
self._entry_data[count + response['start']] = entry
count += 1

def _load_page_for_offset(self, offset):
page = self._get_page_params(offset)
response = self.adapter.request('GET', self.url, page)
self._key_entries(response)

def _get_page_params(self, offset):
"""Return the start and size of the paginated response."""
next_link = self._data.get('next_collection_link', None)
if next_link is None:
"""no more parameters in page!"""
raise StopIteration

url, query = next_link.split('?')
query_parts = parse_qs(query)
self.page_size = int(query_parts['ws.size'][0])
page_number = int(floor(offset / self.page_size))
start = page_number * self.page_size
return {'ws.start': start, 'ws.size': self.page_size}

def create(self, **kwargs):
"""Method to create an item."""
params = {'ws.op': 'create'}
params.update(kwargs)

response = self.adapter.request(
'POST', self.url, params, response='headers')

resource_url = response['location']
data = self.adapter.request('GET', resource_url)
return AWeberEntry(resource_url, data, self.adapter)

def find(self, **kwargs):
"""Method to request a collection."""
params = {'ws.op': 'find'}
params.update(kwargs)
query_string = urlencode(params)
url = '{0.url}?{1}'.format(self, query_string)
data = self.adapter.request('GET', url)

collection = AWeberCollection(url, data, self.adapter)
collection._data['total_size'] = self._get_total_size(url)
return collection

def _get_total_size(self, uri, **kwargs):
"""Get actual total size number from total_size_link."""
total_size_uri = '{0}&ws.show=total_size'.format(uri)
return int(self.adapter.request('GET', total_size_uri))

def get_parent_entry(self):
"""Return a collection's parent entry or None."""
url_parts = self._partition_url()
if url_parts is None:
return None

url = self._construct_parent_url(url_parts, 1)

data = self.adapter.request('GET', url)
try:
entry = AWeberEntry(url, data, self.adapter)

except TypeError:
return None

return entry

def _create_entry(self, offset):
"""Add an entry to the collection"""
data = self._entry_data[offset]
url = data['self_link'].replace(API_BASE, '')
self._entries[offset] = AWeberEntry(url, data, self.adapter)

def __len__(self):
return self.total_size

def __iter__(self):
return self

def next(self):
"""Get the next entry in the collection."""
if self._current < self.total_size:
self._current += 1
return self[self._current - 1]
self._current = 0
raise StopIteration

def __getitem__(self, offset):
if offset < 0 or offset >= self._data['total_size']:
raise ValueError('Offset {0} does not exist'.format(offset))

if not offset in self._entries:
if not offset in self._entry_data:
self._load_page_for_offset(offset)
self._create_entry(offset)
return self._entries[offset]
2 changes: 1 addition & 1 deletion aweber_api/entry.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from urllib import urlencode
from urllib.parse import urlencode

import aweber_api
from aweber_api.data_dict import DataDict
Expand Down
Loading