Moving away from session storage for user email confirmation process

This commit is contained in:
Adolfo Fitoria 2013-06-18 15:36:15 -06:00
parent 48c8d730c2
commit c4151b7752
6 changed files with 188 additions and 33 deletions

View File

@ -36,7 +36,8 @@ REQUIREMENTS = {
'pytz': 'pytz',
'tinymce': 'django-tinymce==1.5.1b2',
'longerusername': 'longerusername',
'bs4': 'beautifulsoup4'
'bs4': 'beautifulsoup4',
'picklefield': 'django-picklefield==0.3.0',
}
if platform.system() != 'Windows':

View File

@ -0,0 +1,134 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'UserEmailVerifier'
db.create_table('django_authopenid_useremailverifier', (
('key', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255, primary_key=True)),
('value', self.gf('picklefield.fields.PickledObjectField')()),
('verified', self.gf('django.db.models.fields.BooleanField')(default=False)),
))
db.send_create_signal('django_authopenid', ['UserEmailVerifier'])
def backwards(self, orm):
# Deleting model 'UserEmailVerifier'
db.delete_table('django_authopenid_useremailverifier')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'languages': ('django.db.models.fields.CharField', [], {'default': "'es-NI'", 'max_length': '128'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
'social_sharing_mode': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'twitter_access_token': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256'}),
'twitter_handle': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'django_authopenid.association': {
'Meta': {'object_name': 'Association'},
'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'issued': ('django.db.models.fields.IntegerField', [], {}),
'lifetime': ('django.db.models.fields.IntegerField', [], {}),
'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
},
'django_authopenid.nonce': {
'Meta': {'object_name': 'Nonce'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'salt': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'server_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'timestamp': ('django.db.models.fields.IntegerField', [], {})
},
'django_authopenid.userassociation': {
'Meta': {'unique_together': "(('user', 'provider_name'), ('openid_url', 'provider_name'))", 'object_name': 'UserAssociation'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_used_timestamp': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'openid_url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'provider_name': ('django.db.models.fields.CharField', [], {'default': "'unknown'", 'max_length': '64'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'django_authopenid.useremailverifier': {
'Meta': {'object_name': 'UserEmailVerifier'},
'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'primary_key': 'True'}),
'value': ('picklefield.fields.PickledObjectField', [], {})
},
'django_authopenid.userpasswordqueue': {
'Meta': {'object_name': 'UserPasswordQueue'},
'confirm_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'new_password': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
}
}
complete_apps = ['django_authopenid']

View File

@ -3,21 +3,24 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from picklefield.fields import PickledObjectField
import hashlib, random, sys, os, time
__all__ = ['Nonce', 'Association', 'UserAssociation',
'UserPasswordQueueManager', 'UserPasswordQueue']
__all__ = ['Nonce', 'Association', 'UserAssociation',
'UserPasswordQueueManager', 'UserPasswordQueue',
'UserEmailVerifier']
class Nonce(models.Model):
""" openid nonce """
server_url = models.CharField(max_length=255)
timestamp = models.IntegerField()
salt = models.CharField(max_length=40)
def __unicode__(self):
return u"Nonce: %s" % self.id
class Association(models.Model):
""" association openid url and lifetime """
server_url = models.TextField(max_length=2047)
@ -26,19 +29,19 @@ class Association(models.Model):
issued = models.IntegerField()
lifetime = models.IntegerField()
assoc_type = models.TextField(max_length=64)
def __unicode__(self):
return u"Association: %s, %s" % (self.server_url, self.handle)
class UserAssociation(models.Model):
"""
model to manage association between openid and user
"""
model to manage association between openid and user
"""
#todo: rename this field so that it sounds good for other methods
#for exaple, for password provider this will hold password
openid_url = models.CharField(blank=False, max_length=255)
user = models.ForeignKey(User)
#in the future this must be turned into an
#in the future this must be turned into an
#association with a Provider record
#to hold things like login badge, etc
provider_name = models.CharField(max_length=64, default='unknown')
@ -49,7 +52,7 @@ class UserAssociation(models.Model):
('user','provider_name'),
('openid_url', 'provider_name')
)
def __unicode__(self):
return "Openid %s with user %s" % (self.openid_url, self.user)
@ -82,3 +85,13 @@ class UserPasswordQueue(models.Model):
def __unicode__(self):
return self.user.username
class UserEmailVerifier(models.Model):
'''Model that stores the required values to verify an email
address'''
key = models.CharField(max_length=255, unique=True, primary_key=True)
value = PickledObjectField()
verified = models.BooleanField(default=False)
def __unicode__(self):
return self.key

View File

@ -81,7 +81,7 @@ import urllib
from askbot import forms as askbot_forms
from askbot.deps.django_authopenid import util
from askbot.deps.django_authopenid import decorators
from askbot.deps.django_authopenid.models import UserAssociation
from askbot.deps.django_authopenid.models import UserAssociation, UserEmailVerifier
from askbot.deps.django_authopenid import forms
from askbot.deps.django_authopenid.backends import AuthBackend
import logging
@ -1019,12 +1019,13 @@ def register(request, login_provider_name=None, user_identifier=None):
cleanup_post_register_session(request)
return HttpResponseRedirect(next_url)
else:
request.session['username'] = username
request.session['email'] = email
key = generate_random_key()
email = request.session['email']
send_email_key(email, key, handler_url_name='verify_email_and_register')
request.session['validation_code'] = key
email_verifier = UserEmailVerifier(key=generate_random_key())
email_verifier.value = {'username': username, 'email': email,
'user_identifier': user_identifier,
'login_provider_name': login_provider_name}
email_verifier.save()
send_email_key(email, email_verifier.key,
handler_url_name='verify_email_and_register')
redirect_url = reverse('verify_email_and_register') + '?next=' + next_url
return HttpResponseRedirect(redirect_url)
@ -1073,14 +1074,16 @@ def verify_email_and_register(request):
try:
#we get here with post if button is pushed
#or with "get" if emailed link is clicked
expected_code = request.session['validation_code']
assert(presented_code == expected_code)
#create an account!
username = request.session['username']
email = request.session['email']
password = request.session.get('password', None)
user_identifier = request.session.get('user_identifier', None)
login_provider_name = request.session.get('login_provider_name', None)
email_verifier = UserEmailVerifier.objects.get(key=presented_code)
#verifies that the code has not been used already
assert(email_verifier.verified == False)
username = email_verifier.value['username']
email = email_verifier.value['email']
password = email_verifier.value.get('password', None)
user_identifier = email_verifier.value.get('user_identifier', None)
login_provider_name = email_verifier.value.get('login_provider_name', None)
if password:
user = create_authenticated_user_account(
username=username,
@ -1098,7 +1101,10 @@ def verify_email_and_register(request):
raise NotImplementedError()
login(request, user)
email_verifier.verified = True
email_verifier.save()
cleanup_post_register_session(request)
return HttpResponseRedirect(get_next_url(request))
except Exception, e:
message = _(
@ -1159,14 +1165,13 @@ def signup_with_password(request):
cleanup_post_register_session(request)
return HttpResponseRedirect(get_next_url(request))
else:
request.session['username'] = username
request.session['email'] = email
request.session['password'] = password
#todo: generate a key and save it in the session
key = generate_random_key()
email = request.session['email']
send_email_key(email, key, handler_url_name='verify_email_and_register')
request.session['validation_code'] = key
email_verifier = UserEmailVerifier(key=generate_random_key())
email_verifier.value = {'username': username,
'login_provider_name': provider_name,
'email': email, 'password': password}
email_verifier.save()
send_email_key(email, email_verifier.key,
handler_url_name='verify_email_and_register')
redirect_url = reverse('verify_email_and_register') + \
'?next=' + get_next_url(request)
return HttpResponseRedirect(redirect_url)

View File

@ -23,3 +23,4 @@ sanction
django-tinymce==1.5.1b2
longerusername
beautifulsoup4
django-picklefield==0.3.0

View File

@ -27,3 +27,4 @@ sanction
django-tinymce
longerusername
beautifulsoup4
django-picklefield==0.3.0