Skip to content

Commit

Permalink
first pass at basic invitation system
Browse files Browse the repository at this point in the history
  • Loading branch information
tswicegood committed Nov 10, 2009
1 parent a1c18b8 commit 5a94c00
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 0 deletions.
11 changes: 11 additions & 0 deletions d51/django/apps/invites/fields.py
@@ -0,0 +1,11 @@
from django import forms
from django.forms.fields import EmailField

def check(email):
field = EmailField()
return field.clean(email.strip())

class MultiEmailField(forms.Field):
def clean(self, value):
return [check(email) for email in value.split(',')]

20 changes: 20 additions & 0 deletions d51/django/apps/invites/forms.py
@@ -0,0 +1,20 @@
from django import forms
from d51.django.apps.invites.fields import MultiEmailField

email_attrs = {
'class': 'required',
'max_length': 100,
}

class InvitationForm(forms.Form):
"""
Form for sending invitations
"""
from_email = forms.EmailField(widget=forms.TextInput(attrs=email_attrs))
to_email = MultiEmailField(widget=forms.TextInput(attrs=email_attrs))

personal_note = forms.CharField(
required=False,
widget=forms.Textarea()
)

2 changes: 2 additions & 0 deletions d51/django/apps/invites/templates/invites/base.html
@@ -0,0 +1,2 @@
{% extends "base.html" %}

@@ -0,0 +1,9 @@
{% load i18n %}
<form action="{% url invites_index %}" method="POST">
{{ invitation_form.as_p }}

<div class="controls">
<input type="submit" value="{% trans 'Send Invitation' %}" />
</div>
</form>

5 changes: 5 additions & 0 deletions d51/django/apps/invites/templates/invites/index.html
@@ -0,0 +1,5 @@
{% extends "invites/base.html" %}

{% block content %}
{% include "invites/fragments/invitation_form.html" %}
{% endblock %}
11 changes: 11 additions & 0 deletions d51/django/apps/invites/templates/invites/thanks.html
@@ -0,0 +1,11 @@
{% extends "invites/base.html" %}
{% load i18n %}

{% block content %}
<h2>{% trans "Thanks!" %}</h2>

<p>
Thanks for inviting {{ number_of_invites }}
{% ifequal number_of_invites 1 %}person{% else %}people{% endifequal %}
</p>
{% endblock %}
5 changes: 5 additions & 0 deletions d51/django/apps/invites/tests/__init__.py
@@ -0,0 +1,5 @@
from d51.django.apps.invites.tests.fields import *
from d51.django.apps.invites.tests.forms import *
from d51.django.apps.invites.tests.views import *


17 changes: 17 additions & 0 deletions d51/django/apps/invites/tests/fields.py
@@ -0,0 +1,17 @@
from django.forms.util import ValidationError
from django.test import TestCase
from d51.django.apps.invites.fields import MultiEmailField

class MultiEmailFieldTest(TestCase):
def test_allows_multiple_emails(self):
field = MultiEmailField()
expected = ["bob@example.com", "alice@example.com",]
actual = field.clean(", ".join(expected))
self.assert_(expected[0] in actual)
self.assert_(expected[1] in actual)

def test_throws_validation_error_if_bad_email_provided(self):
bad_data = "bob@example.com, alice@bad"
field = MultiEmailField()
self.assertRaises(ValidationError, field.clean, bad_data)

12 changes: 12 additions & 0 deletions d51/django/apps/invites/tests/forms.py
@@ -0,0 +1,12 @@
from django.test import TestCase
from d51.django.apps.invites.forms import InvitationForm

class InvitationFormTests(TestCase):
def test_allows_multiple_emails_in_to_field(self):
form = InvitationForm({
"from_email": "travis@example.com",
"to_email": "bob@example.com, alice@example.com",
})

self.assert_(form.is_valid())

25 changes: 25 additions & 0 deletions d51/django/apps/invites/tests/views.py
@@ -0,0 +1,25 @@
from django.core import mail
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.client import Client
from d51.django.apps.invites.views import index, thanks

class IndexViewTests(TestCase):
def test_renders_invites_index_html_on_GET(self):
c = Client()
response = c.get(reverse("invites_index"))
self.assertEqual(200, response.status_code)

def test_redirects_to_thanks_on_successful_POST(self):
c = Client()
response = c.post(reverse("invites_index"), {
"from_email": "travis@example.com",
"to_email": "bob@example.com"
})
self.assertEqual(302, response.status_code)
redirect = response._headers['location']
self.assertEqual(
reverse("invites_thanks")+"?num=1",
redirect[1][-len(reverse("invites_thanks")+"?num=1"):]
)

7 changes: 7 additions & 0 deletions d51/django/apps/invites/urls.py
@@ -0,0 +1,7 @@
from django.conf.urls.defaults import patterns, url

urlpatterns = patterns('d51.django.apps.invites.views',
url(r'^$', 'index', name='invites_index'),
url(r'^thanks/$', 'thanks', name='invites_thanks'),
)

39 changes: 39 additions & 0 deletions d51/django/apps/invites/views.py
@@ -0,0 +1,39 @@
from django.conf import settings
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from d51.django.apps.invites.forms import InvitationForm


def index(request):
if request.method == "POST":
form = InvitationForm(request.POST)
if form.is_valid():
to_emails = form.cleaned_data['to_email']
# TODO: handle error cases
send_mail(
'Subject',
'Our message',
form.cleaned_data['from_email'],
to_emails
)
return redirect(reverse('invites_thanks') + '?num=%d' % len(to_emails))
else:
form = InvitationForm()

return render_to_response(
'invites/index.html',
{
'invitation_form': form,
},
context_instance=RequestContext(request)
)
def thanks(request):
return render_to_response(
'invites/thanks.html',
{
'number_of_invites': int(request.GET['num']),
},
context_instance=RequestContext(request))

Empty file.
1 change: 1 addition & 0 deletions project-for-testing/urls.py
Expand Up @@ -8,6 +8,7 @@

urlpatterns = patterns(
'',
(r'^invites/', include('d51.django.apps.invites.urls')),
(r'^admin/(.*)', admin.site.root),
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
)
Expand Down

0 comments on commit 5a94c00

Please sign in to comment.