Skip to content

Commit

Permalink
Registration is working and tested.
Browse files Browse the repository at this point in the history
  • Loading branch information
Luke Sneeringer committed Feb 26, 2012
1 parent 299bc78 commit 1a3de1a
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 25 deletions.
1 change: 1 addition & 0 deletions settings/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.transaction.TransactionMiddleware',
'tools.middleware.JinjaMiddleware',
)

Expand Down
26 changes: 23 additions & 3 deletions wedding/accounts/forms.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
from django import forms
from django.contrib.auth.forms import UserCreationForm
from wedding.reservations.models import Invitation


class RegistrationForm(UserCreationForm):
code = forms.CharField(
help_text='Enter the code provided to you on your invitation response card. Case insensitive.',
token = forms.CharField(
help_text='Enter the token provided to you on your invitation response card. Case insensitive.',
max_length=11,
)
)

def clean_token(self):
"""Ensure validity of the user's registration token."""

# transform this code to all lowercase, and remove the hyphen
# if it's present
token = self.cleaned_data['token'].replace('-', '').lower()

# if the token is not in the database, then error out
if Invitation.objects.filter(token=token).count() == 0:
raise forms.ValidationError, 'That token was not found.'

# another possibility is that the token has already been used--test for this;
# don't allow multiple accounts on the same invitation
if Invitation.objects.filter(token=token).exclude(user=None).count() > 0:
raise forms.ValidationError, 'There is already a user account registered for this token.'

# okay, we're good to go...
return token
21 changes: 21 additions & 0 deletions wedding/accounts/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from django.core.urlresolvers import reverse
from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from wedding.accounts.forms import RegistrationForm
from wedding.reservations.models import Invitation


def register(request):
Expand All @@ -8,6 +12,23 @@ def register(request):
# sanity check: is this a processing request?
if request.method == 'POST':
form = RegistrationForm(request.POST)

# if the form is valid, create the user, log them in,
# and send them on their way
if form.is_valid():
user = form.save()

# associate the correct invitation with the user
invitation = Invitation.objects.get(token=form.cleaned_data['token'])
invitation.user = user
invitation.save()

# automatically log the user in
user = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password1'])
login(request, user)

# they probably want to go to the rsvp section...
return HttpResponseRedirect(reverse('rsvp'))
else:
form = RegistrationForm()

Expand Down
1 change: 1 addition & 0 deletions wedding/reservations/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class InviteeInline(admin.TabularInline):
@admin_register(Invitation)
class InvitationAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'token', 'address', 'city', 'state', 'zip_code')
exclude = ('token',)
inlines = (InviteeInline,)


Expand Down
50 changes: 42 additions & 8 deletions wedding/reservations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
class Invitation(models.Model):
"""A single invitation sent to a family at a given address."""

user = models.ForeignKey(User, null=True, blank=True)
token = models.CharField(max_length=8)
user = models.OneToOneField(User, null=True, blank=True)
token = models.CharField(max_length=8, blank=True)
address = models.CharField(max_length=100)
city = models.CharField(max_length=30)
state = models.CharField(max_length=2)
Expand All @@ -18,8 +18,18 @@ class Invitation(models.Model):
modified = models.DateTimeField(auto_now=True)

def __unicode__(self):
return self.formal_name

def __len__(self):
return self.invitee_set.count()

def __nonzero__(self):
return True

@cached_property
def formal_name(self):
"""Return the formal name used to address this invitation."""

# if there is only one adult, use the adult's formal name
if len(self.adults) == 1:
return unicode(self.adults[0])
Expand All @@ -37,14 +47,37 @@ def __unicode__(self):

# okay, the last names don't match; print the names out separately
# and in their entirety
# (e.g. "Mr. Daniel Beltz and Ms. Jessica Dymer")
# (e.g. "Mr. Daniel Beltz and Miss Jessica Dymer")
return u'%s & %s' % (self.adults[0], self.adults[1])

def __len__(self):
return self.invitee_set.count()
@cached_property
def informal_name(self):
"""Return a less formal version of the names of the adults
on this invitation."""

def __nonzero__(self):
return True
# if there is only one adult, use the adult's first and last name
if len(self.adults) == 1:
return u'%s %s' % (self.adults[0].first_name, self.adults[0].last_name)

# okay, there are two adults -- if their last names match,
# then return a single format with both informal first names but the shared
# last name (e.g. "Jon and Andi Chappell")
if self.adults[0].last_name == self.adults[1].last_name:
return u'%(male_first_name)s & %(female_first_name)s %(last_name)s' % {
'female_first_name': self.adults[1].nickname,
'male_first_name': self.adults[0].nickname,
'last_name': self.adults[0].last_name,
}

# okay, there are two adults with different last names; print
# them out separately but with no titles
# (e.g. "Dan Beltz & Jess Dymer")
return u'%(male_first_name)s %(male_last_name)s & %(female_first_name)s %(female_last_name)s' % {
'female_first_name': self.adults[1].nickname,
'female_last_name': self.adults[1].last_name,
'male_first_name': self.adults[0].nickname,
'male_last_name': self.adults[0].last_name,
}

@cached_property
def adults(self):
Expand Down Expand Up @@ -78,6 +111,7 @@ class Invitee(models.Model):
title = models.CharField(max_length=16)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
nickname = models.CharField(max_length=16, blank=True, help_text='An informal or short name, if the person uses one (e.g. "Elli", "Jon").')
age_group = models.CharField(max_length=6, choices=(
('adult', 'Adult'),
('child', 'Child (2 - 16 years)'),
Expand Down
9 changes: 7 additions & 2 deletions wedding/reservations/signals.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from django.dispatch import receiver
from django.db.models.signals import pre_save
from random import choice
from wedding.reservations.models import Invitation
from wedding.reservations.models import Invitation, Invitee


@receiver(pre_save, sender=Invitation)
def on_invitation_save(sender, instance, **kwargs):
if not instance.token:
instance.token = ''.join([choice('23456789abcdefghjkmnpqrstuvwxyz') for i in range(0,8)])
instance.token = ''.join([choice('23456789abcdefghjkmnpqrstuvwxyz') for i in range(0,8)])

@receiver(pre_save, sender=Invitee)
def on_invitee_save(sender, instance, **kwargs):
if not instance.nickname:
instance.nickname = instance.first_name
4 changes: 2 additions & 2 deletions wedding/reservations/templates/reservations/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
{% block content %}
<h1>Reservations</h1>

{% if invitation.response is not none %}
{% if invitation.attending is not none %}
<p>Thank you for responding; we have your RSVP on file,
{% if invitation.response %}and we're very glad that you will{% else -%}
{% if invitation.attending %}and we're very glad that you will{% else -%}
although we're sad that you will not{% endif %} be able to join us.
</p>

Expand Down
10 changes: 3 additions & 7 deletions wedding/reservations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,18 @@
def index(request):
"""Return the RSVP landing page."""

# pull up the invitation attached to this user
invitation = Invitation.objects.get(user=request.user)

# send down a template with reservation details
return TemplateResponse(request, 'reservations/index.html', {
'invitation': invitation,
'invitation': request.user.invitation,
})


@login_required
def rsvp_form(request):
"""Provide or process a form for editing an RSVP."""

# first, pull up the invitation and the reservation (if any)
# for this user
invitation = Invitation.objects.get(user=request.user)
invitation = request.user.invitation

# okay, am I processing the form?
forms = []
Expand Down Expand Up @@ -59,7 +55,7 @@ def rsvp_thanks(request):
"""Landing page for a successful RSVP."""

# retrieve the invitation
invitation = Invitation.objects.get(user=request.user)
invitation = request.user.invitation

# return the template
return TemplateResponse(request, 'reservations/thanks.html', {
Expand Down
5 changes: 3 additions & 2 deletions wedding/static/static/css/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,10 @@ nav a.selected {
/* footer */
footer {
top: 4px;
color: #808080;
font-family: Tahoma, Arial, Sans-Serif;
color: #606060;
font-family: Georgia, Times, Serif;
font-size: 10px;
font-style: italic;
position: fixed;
text-align: right;
width: 960px;
Expand Down
2 changes: 1 addition & 1 deletion wedding/static/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ <h1>{{ title }}</h1>
</div>
<footer>
{% if not user.is_anonymous() %}
logged in as <b>{{ user.username }}</b>:
logged in as <b>{{ user.invitation.informal_name }}</b>:
{% if user.is_superuser %}<a href="/admin/">admin</a> | {% endif %}
<a href="{{ url('password-change') }}">change password</a> |
<a href="{{ url('logout') }}">logout</a>
Expand Down

0 comments on commit 1a3de1a

Please sign in to comment.