Skip to content
Browse files

refactor and flesh out into full basket library

  • Loading branch information...
1 parent 2f8953b commit aa91c00c250a6230aeec17e68607204ac134c4c5 @jlongster jlongster committed Nov 30, 2011
Showing with 120 additions and 29 deletions.
  1. +1 −1 basket/__init__.py
  2. +112 −17 basket/base.py
  3. +7 −11 setup.py
View
2 basket/__init__.py
@@ -1 +1 @@
-from base import subscribe
+from base import subscribe, unsubscribe, user, update_user, debug_user
View
129 basket/base.py
@@ -1,6 +1,35 @@
+"""This is a client for Mozilla's email subscription service,
+basket. Basket is not a real subscription service, but it talks to a
+real one and we don't really care who/what it is.
+
+There are four API methods: subscribe, unsubscribe, user, and
+update_user. View the basket documentation [1] for details.
+
+***
+
+Are you looking to integrate this on a site for email subscriptions?
+All you need to do is:
+
+import basket
+basket.subscribe('<email>', '<newsletter>', <kwargs>)
+
+You can pass additional fields as keyword arguments, such as format
+and country. For a list of available fields, see the basket documentation [1].
+
+***
+
+Are you checking to see if a user was successfully subscribed?
+
+[1] https://github.com/mozilla/basket/tree/master/apps/news
+"""
+
import json
-from django.conf import settings
+try:
+ from django.conf import settings
+ BASKET_URL = settings.BASKET_URL
+except ImportError:
+ BASKET_URL = 'https://basket.mozilla.com'
import requests
@@ -9,30 +38,96 @@ class BasketException(Exception):
pass
+def basket_url(method, token=None):
+ """Form a basket API url. If the request requires a user-specific
+ token, it is suffixed as the last part of the URL."""
+
+ token = '%s/' % token if token else ''
+
+ return ('%s/news/%s/%s' % (BASKET_URL, method, token))
+
+def parse_response(res):
+ """Parse the result of a basket API call, raise exception on error"""
+
+ if res.error:
+ raise BasketException('Error connecting to %s: %s. Ensure that '
+ 'BASKET_URL is configured correctly in your '
+ 'settings file.' % (res.url, res.error))
+
+ if res.status_code != 200:
+ raise BasketException('%s request returned from basket: %s' %
+ (res.status_code, res.content))
+
+ # Parse the json and check for errors
+ result = json.loads(res.content)
+
+ if result.get('status') == 'error':
+ raise BasketException(result['desc'])
+
+ return result
+
+
+def request(method, action, data=None, token=None, params=None):
+ """Call the basket API with the supplied http method and data."""
+
+ # newsletters should be comma-delimited
+ if data and 'newsletters' in data:
+ if '__iter__' in data['newsletters']:
+ data['newsletters'] = ','.join(data['newsletters'])
+
+ res = requests.request(method,
+ basket_url(action, token),
+ data=data,
+ params=params)
+ return parse_response(res)
+
+
+# Public API methods
+
def subscribe(email, newsletters, **kwargs):
+ """Subscribe an email through basket to `newsletters`, which can
+ be string or an array of newsletter names. Additional parameters
+ should be passed as keyword arguments."""
+
kwargs.update(email=email, newsletters=newsletters)
- return _post('subscribe', kwargs)
+ print kwargs
+ return request('post', 'subscribe', data=kwargs)
-def _url(path):
- return 'https://%s/news/%s/' % (settings.BASKET_URL, path)
+def unsubscribe(token, email, newsletters=None, optout=False):
+ """Unsubscribe an email from certain newsletters, or all of them
+ if `optout` is passed. Requires a token."""
-def _post(path, data):
- return _parse_response(requests.post(_url(path), data=data))
+ data = {'email': email}
+ if optout:
+ data['optout'] = 'Y'
+ elif newsletters:
+ data['newsletters'] = newsletters
+ else:
+ raise BasketException('unsubscribe requires ether a newsletters '
+ 'or optout parameter')
-def _get(path, data):
- return _parse_response(requests.get(_url(path), data=data))
+ return request('post', 'unsubscribe', data=data, token=token)
-def _parse_response(response):
- if response.error:
- raise BasketException('Error connecting to %s: %s. Ensure that '
- 'BASKET_URL is configured correctly in your '
- 'settings file.' % (response.url, response.error))
+def user(token):
+ """Get all the information about a user. Requires a token."""
+ return request('get', 'user', token=token)
+
+
+def update_user(token, **kwargs):
+ """Update any fields for a user. Requires a token. If newsletters
+ is passed, the user is only subscribed to those specific
+ newsletters."""
+
+ return request('post', 'user', data=kwargs, token=token)
+
- response_json = json.loads(response.content)
- if response_json.get('desc', None):
- raise BasketException(response_json['desc'])
+def debug_user(email, supertoken):
+ """Get a user's information using a supertoken only known by devs,
+ useful for ensuring that data is being posted correctly"""
- return response_json
+ return request('get', 'debug-user',
+ params={'email': email,
+ 'supertoken': supertoken})
View
18 setup.py
@@ -3,25 +3,21 @@
setup(
name='basket',
- version='0.1.0',
- description='A thin, practical wrapper around terminal formatting, positioning, and more',
+ version='0.2.0',
+ description="A Python client for Mozilla's basket service",
long_description=open('README.rst').read(),
- author='Erik Rose',
- author_email='erikrose@grinchcentral.com',
+ author='Michael Kelly',
+ author_email='mkelly@mozilla.com',
license='GPL',
packages=find_packages(exclude=['ez_setup']),
- tests_require=['Nose'],
- url='https://github.com/erikrose/blessings',
+ install_requires=['requests'],
+ url='https://github.com/Osmose/basket-client',
include_package_data=True,
classifiers=[
'Intended Audience :: Developers',
'Natural Language :: English',
- 'Environment :: Console',
- 'Operating System :: POSIX',
'Topic :: Software Development :: Libraries',
- 'Topic :: Software Development :: User Interfaces',
- 'Topic :: Terminals'
],
- keywords=['terminal', 'tty', 'curses', 'formatting', 'color'],
+ keywords=['mozilla', 'basket'],
**extra_setup
)

0 comments on commit aa91c00

Please sign in to comment.
Something went wrong with that request. Please try again.