Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Commit

Permalink
create news app, basic HTTP API for subscribing
Browse files Browse the repository at this point in the history
  • Loading branch information
jlongster committed Jul 14, 2011
1 parent d77bb65 commit 9c729a5
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 27 deletions.
Empty file added apps/news/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions apps/news/models.py
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
13 changes: 13 additions & 0 deletions apps/news/news.html
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form action="http://localhost:8000/news/subscribe/" method="post">
<div>
Email: <input type="text" name="email" />
</div>
<input type="submit" />
</form>
</body>
</html>
102 changes: 102 additions & 0 deletions apps/news/responsys.py
@@ -0,0 +1,102 @@
from functools import wraps

from suds import WebFault
from suds.client import Client


class UnathorizedException(Exception):
pass


def logged_in(f):
""" Decorator to ensure an authenticated session with Responsys
before calling a function """

@wraps(f)
def wrapper(inst, *args, **kwargs):
if not inst.session:
raise UnauthorizedException("Not logged in to Responsys, "
"must call login()")
f(inst, *args, **kwargs)
return wrapper


class Responsys(object):
WSDL_URL = 'https://ws2.responsys.net/webservices/wsdl/ResponsysWS_Level1.wsdl'

def __init__(self):
self.client = None
self.session = None

def login(self, user, pass_):
""" Login and create a Responsys session, returns False on
failure """

if not self.client:
self.client = Client(self.__class__.WSDL_URL)
elif self.session:
self.logout()

try:
res = self.client.service.login(user, pass_)
except WebFault, e:
return False

self.session = res['sessionId']

# Set auth token for all requests
header = self.client.factory.create('SessionHeader')
header.sessionId = self.session
self.client.set_options(soapheaders=header)

@logged_in
def logout(self):
""" Logout and expire the current Responsys session """

self.client.service.logout()
self.session = None

@logged_in
def merge_list_members(self, folder, list_, fields, records):
"""
Add data to the list located at <folder>/<list_> in
Responsys.
<fields> is an array of field names
<records> is a single record or an array of records to insert
(record = array). If the email already exists, its data will
be updated
"""

client = self.client
records = [records] if isinstance(records[0], basestring) else records

def make_record(record):
data = client.factory.create('Record')
data.fieldValues = record
return data

target = client.factory.create('InteractObject')
target.folderName = folder
target.objectName = list_

data = client.factory.create('RecordData')
data.fieldNames = fields
data.records = [make_record(r) for r in records]

# Configure the action to update the data when it matches on
# the email address field, otherwise insert a new entry, and
# default opt in
rule = client.factory.create('ListMergeRule')
rule.insertOnNoMatch = True
rule.updateOnMatch = 'REPLACE_ALL'
rule.matchColumnName1 = 'EMAIL_ADDRESS_'
rule.matchOperator = 'NONE'
rule.optinValue = 'I'
rule.optoutValue = 'O'
rule.htmlValue = 'H'
rule.textValue = 'T'
rule.rejectRecordIfChannelEmpty = 'E'
rule.defaultPermissionStatus = 'OPTIN'

self.client.service.mergeListMembers(target, data, rule)
23 changes: 23 additions & 0 deletions apps/news/tests.py
@@ -0,0 +1,23 @@
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""

from django.test import TestCase

class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)

__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}

6 changes: 6 additions & 0 deletions apps/news/urls.py
@@ -0,0 +1,6 @@
from django.conf.urls.defaults import *
from views import subscribe

urlpatterns = patterns('',
url('^subscribe/$', subscribe),
)
53 changes: 53 additions & 0 deletions apps/news/views.py
@@ -0,0 +1,53 @@
from datetime import date
import urlparse

from django.http import (HttpResponse, HttpResponseRedirect,
HttpResponseBadRequest, HttpResponseForbidden)
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings

from responsys import Responsys


@csrf_exempt
def subscribe(request):
if request.method == 'POST':
data = request.POST

# validate parameters
for name in ['email']:
if name not in data:
return HttpResponseBadRequest('%s is missing' % name)

record = {'EMAIL_ADDRESS_': data['email'],
'EMAIL_FORMAT_': data.get('format', 'H'),
'COUNTRY_': data.get('country', 'en'),
'MOZILLA_AND_YOU_FLG': 'Y',
'MOZILLA_AND_YOU_DATE': date.today().strftime('%Y-%m-%d')}

# do the subscription
rs = Responsys()
rs.login(settings.RESPONSYS_USER, settings.RESPONSYS_PASS)
rs.merge_list_members(settings.RESPONSYS_FOLDER,
settings.RESPONSYS_LIST,
record.keys(),
record.values())
rs.logout()

# redirect back to the page, if any
next = data.get('next', request.META.get('HTTP_REFERER', None))
if next:
parts = urlparse.urlsplit(next)
query = '%s%s%s' % (parts.query,
'&' if parts.query else '',
'subscribed')
next = urlparse.urlunsplit((parts.scheme,
parts.netloc,
parts.path,
query,
parts.fragment))
return HttpResponseRedirect(next)
return HttpResponse('Success! You have been subscribed.')

return HttpResponseBadRequest('GET is not supported')

35 changes: 8 additions & 27 deletions settings.py
Expand Up @@ -29,39 +29,17 @@
}
}

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = path('media')

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = '/media/'

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/admin-media/'

# Make this unique, and don't share it with anybody.
SECRET_KEY = ''
SECRET_KEY = '0D8AE44F-5714-40EF-9AC8-4AC6EB556161'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
Expand Down Expand Up @@ -95,6 +73,7 @@
'nagios',
'subscriptions',
'vars',
'news',

'fixture_magic',
'piston',
Expand Down Expand Up @@ -129,7 +108,7 @@
DEFAULT_FROM_NAME = 'Mozilla'

# Logging
LOG_LEVEL = logging.DEBUG
LOG_LEVEL = logging.INFO
HAS_SYSLOG = True # syslog is used if HAS_SYSLOG and NOT DEBUG.
SYSLOG_TAG = "http_app_basket"
# See PEP 391 and log_settings.py for formatting help. Each section of LOGGING
Expand All @@ -150,11 +129,8 @@
}

EMAIL_BACKEND = 'mysmtp.EmailBackend'

EMAIL_BACKLOG_TOLERANCE = 200

SYNC_UNSUBSCRIBE_LIMIT = 1000

LDAP_TIMEOUT = 2

def JINJA_CONFIG():
Expand All @@ -164,3 +140,8 @@ def JINJA_CONFIG():
'jinja2.ext.with_', 'jinja2.ext.loopcontrols'],
'finalize': lambda x: x if x is not None else ''}
return config

RESPONSYS_USER = 'MOZILLA_API'
RESPONSYS_PASS = ''
RESPONSYS_FOLDER = '!MasterData'
RESPONSYS_LIST = 'TEST_CONTACTS_LIST'
1 change: 1 addition & 0 deletions urls.py
Expand Up @@ -9,6 +9,7 @@
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
(r'^admin/', include(admin.site.urls)),
('^nagios/', include('nagios.urls')),
(r'^news/', include('news.urls'))
)

if settings.DEBUG:
Expand Down

0 comments on commit 9c729a5

Please sign in to comment.