Files
edx-platform/student/views.py
David Ormsbee b54ff42532 add caching to User and UserProfile
--HG--
branch : dormsbee_performance
2012-02-23 20:09:15 -05:00

255 lines
10 KiB
Python

import json
import logging
import random
import string
from django.conf import settings
from django.contrib.auth import logout, authenticate, login
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.models import User
from django.core.context_processors import csrf
from django.core.validators import validate_email, validate_slug
from django.db import connection
from django.http import HttpResponse, Http404
from django.shortcuts import redirect
from mitxmako.shortcuts import render_to_response, render_to_string
from models import Registration, UserProfile
from django_future.csrf import ensure_csrf_cookie
log = logging.getLogger("mitx.user")
def csrf_token(context):
csrf_token = context.get('csrf_token', '')
if csrf_token == 'NOTPROVIDED':
return ''
return u'<div style="display:none"><input type="hidden" name="csrfmiddlewaretoken" value="%s" /></div>' % (csrf_token)
@ensure_csrf_cookie
def index(request):
if settings.COURSEWARE_ENABLED and request.user.is_authenticated():
return redirect('/info')
else:
csrf_token = csrf(request)['csrf_token']
# TODO: Clean up how 'error' is done.
return render_to_response('index.html', {'csrf': csrf_token })
# Need different levels of logging
@ensure_csrf_cookie
def login_user(request, error=""):
if 'email' not in request.POST or 'password' not in request.POST:
return HttpResponse(json.dumps({'success':False,
'error': 'Invalid login'})) # TODO: User error message
email = request.POST['email']
password = request.POST['password']
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
log.warning("Login failed - Unknown user email: {0}".format(email))
return HttpResponse(json.dumps({'success':False,
'error': 'Invalid login'})) # TODO: User error message
username = user.username
user = authenticate(username=username, password=password)
if user is None:
log.warning("Login failed - password for {0} is invalid".format(email))
return HttpResponse(json.dumps({'success':False,
'error': 'Invalid login'}))
if user is not None and user.is_active:
try:
login(request, user)
if request.POST['remember'] == 'true':
request.session.set_expiry(None) # or change to 604800 for 7 days
log.debug("Setting user session to never expire")
else:
request.session.set_expiry(0)
except Exception as e:
log.critical("Login failed - Could not create session. Is memcached running?")
log.exception(e)
log.info("Login success - {0} ({1})".format(username, email))
return HttpResponse(json.dumps({'success':True}))
log.warning("Login failed - Account not active for user {0}".format(username))
return HttpResponse(json.dumps({'success':False,
'error': 'Account not active. Check your e-mail.'}))
@ensure_csrf_cookie
def logout_user(request):
logout(request)
# print len(connection.queries), connection.queries
return redirect('/')
@ensure_csrf_cookie
def change_setting(request):
if not request.user.is_authenticated():
return redirect('/')
up = request.user.profile_cache # UserProfile.objects.get(user=request.user)
if 'location' in request.POST:
# print "loc"
up.location=request.POST['location']
if 'language' in request.POST:
# print "lang"
up.language=request.POST['language']
up.save()
return HttpResponse(json.dumps({'success':True,
'language':up.language,
'location':up.location,}))
@ensure_csrf_cookie
def create_account(request, post_override=None):
js={'success':False}
post_vars = post_override if post_override else request.POST
# Confirm we have a properly formed request
for a in ['username', 'email', 'password', 'location', 'language', 'name']:
if a not in post_vars:
js['value']="Error (401 {field}). E-mail us.".format(field=a)
return HttpResponse(json.dumps(js))
if post_vars['honor_code']!=u'true':
js['value']="To enroll, you must follow the honor code.".format(field=a)
return HttpResponse(json.dumps(js))
if post_vars['terms_of_service']!=u'true':
js['value']="You must accept the terms of service.".format(field=a)
return HttpResponse(json.dumps(js))
# Confirm appropriate fields are there.
# TODO: Check e-mail format is correct.
# TODO: Confirm e-mail is not from a generic domain (mailinator, etc.)? Not sure if
# this is a good idea
# TODO: Check password is sane
for a in ['username', 'email', 'name', 'password', 'terms_of_service', 'honor_code']:
if len(post_vars[a])<2:
error_str = {'username' : 'Username of length 2 or greater',
'email' : 'Properly formatted e-mail',
'name' : 'Your legal name ',
'password': 'Valid password ',
'terms_of_service': 'Accepting Terms of Service',
'honor_code': 'Agreeing to the Honor Code'}
js['value']="{field} is required.".format(field=error_str[a])
return HttpResponse(json.dumps(js))
try:
validate_email(post_vars['email'])
except:
js['value']="Valid e-mail is required.".format(field=a)
return HttpResponse(json.dumps(js))
try:
validate_slug(post_vars['username'])
except:
js['value']="Username should only consist of A-Z and 0-9.".format(field=a)
return HttpResponse(json.dumps(js))
# Confirm username and e-mail are unique. TODO: This should be in a transaction
if len(User.objects.filter(username=post_vars['username']))>0:
js['value']="An account with this username already exists."
return HttpResponse(json.dumps(js))
if len(User.objects.filter(email=post_vars['email']))>0:
js['value']="An account with this e-mail already exists."
return HttpResponse(json.dumps(js))
u=User(username=post_vars['username'],
email=post_vars['email'],
is_active=False)
u.set_password(post_vars['password'])
r=Registration()
# TODO: Rearrange so that if part of the process fails, the whole process fails.
# Right now, we can have e.g. no registration e-mail sent out and a zombie account
u.save()
r.register(u)
up = UserProfile(user=u)
up.name=post_vars['name']
up.language=post_vars['language']
up.location=post_vars['location']
up.save()
d={'name':post_vars['name'],
'key':r.activation_key,
'site':settings.SITE_NAME}
subject = render_to_string('activation_email_subject.txt',d)
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
message = render_to_string('activation_email.txt',d)
try:
if not settings.GENERATE_RANDOM_USER_CREDENTIALS:
res=u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
except:
js['value']=str(sys.exc_info())
return HttpResponse(json.dumps(js))
js={'success':True,
'value':render_to_string('registration/reg_complete.html', {'email':post_vars['email'],
'csrf':csrf(request)['csrf_token']})}
# print len(connection.queries), connection.queries
return HttpResponse(json.dumps(js), mimetype="application/json")
def create_random_account(create_account_function):
def id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for x in range(size))
def inner_create_random_account(request):
post_override= {'username' : "random_" + id_generator(),
'email' : id_generator(size=10, chars=string.ascii_lowercase) + "_dummy_test@mitx.mit.edu",
'password' : id_generator(),
'location' : id_generator(size=5, chars=string.ascii_uppercase),
'language' : id_generator(size=5, chars=string.ascii_uppercase) + "ish",
'name' : id_generator(size=5, chars=string.ascii_lowercase) + " " + id_generator(size=7, chars=string.ascii_lowercase),
'honor_code' : u'true',
'terms_of_service' : u'true',}
# print "Creating random account: " , post_override
return create_account_function(request, post_override = post_override)
return inner_create_random_account
if settings.GENERATE_RANDOM_USER_CREDENTIALS:
create_account = create_random_account(create_account)
@ensure_csrf_cookie
def activate_account(request, key):
r=Registration.objects.filter(activation_key=key)
if len(r)==1:
if not r[0].user.is_active:
r[0].activate()
resp = render_to_response("activation_complete.html",{'csrf':csrf(request)['csrf_token']})
return resp
resp = render_to_response("activation_active.html",{'csrf':csrf(request)['csrf_token']})
return resp
if len(r)==0:
return render_to_response("activation_invalid.html",{'csrf':csrf(request)['csrf_token']})
return HttpResponse("Unknown error. Please e-mail us to let us know how it happened.")
@ensure_csrf_cookie
def password_reset(request):
''' Attempts to send a password reset e-mail. '''
if request.method != "POST":
raise Http404
form = PasswordResetForm(request.POST)
if form.is_valid():
form.save( use_https = request.is_secure(),
from_email = settings.DEFAULT_FROM_EMAIL,
request = request )
return HttpResponse(json.dumps({'success':True,
'value': render_to_string('registration/password_reset_done.html', {})}))
else:
return HttpResponse(json.dumps({'success':False,
'error': 'Invalid e-mail'}))