You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
6.9 KiB
Python

from __future__ import unicode_literals
from random import choice, sample
import string
from django.utils.timezone import now as tznow
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import login_required
from django.contrib.auth import get_user_model
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.template.defaultfilters import slugify
try:
from django.urls import reverse
except ImportError: # Django < 1.10
from django.core.urlresolvers import reverse
from nano.tools import pop_error, get_profile_model, asciify
from nano.user.forms import SignupForm, PasswordChangeForm, PasswordResetForm
from nano.user import new_user_created
import logging
_LOG = logging.getLogger(__name__)
class NanoUserError(Exception):
pass
class NanoUserExistsError(NanoUserError):
pass
# def pop_error(request):
# error = request.session.get('error', None)
# if 'error' in request.session:
# del request.session['error']
# return error
def random_password():
sample_space = string.ascii_letters + string.digits + r'!#$%&()*+,-.:;=?_'
outlist = []
for i in range(1,8):
chars = sample(sample_space, 2)
outlist.extend(chars)
return ''.join(outlist)
def make_user(username, password, email=None, request=None):
User = get_user_model()
try:
User.objects.get(username=username)
except User.DoesNotExist:
# make user
user = User(username=username[:30])
user.set_password(password)
user.is_staff = False
user.is_superuser = False
user.is_active = True
if email:
user.email = email
user.save()
# Create profile
Profile = get_profile_model(raise_on_error=False)
if Profile:
profile = Profile(user=user, display_name=username)
profile.save()
# Don't signal creation of test users
test_users = getattr(settings, 'NANO_USER_TEST_USERS', ())
for test_user in test_users:
if user.username.startswith(test_user):
break
else:
new_user_created.send(sender=User, user=user)
if request is not None:
infomsg = 'You\'re now registered, as "%s"' % username
messages.info(request, infomsg)
_LOG.debug('Created user: %s/%s' % (user, user.check_password(password)))
return user
else:
raise NanoUserExistsError("The username '%s' is already in use by somebody else" % username)
def signup(request, template_name='signup.html', *args, **kwargs):
me = 'people'
error = pop_error(request)
data = {
'me': me,
'error': error,
'form': SignupForm()
}
if request.method == 'POST':
form = SignupForm(data=request.POST)
if form.is_valid():
username = asciify(form.cleaned_data['username'])
password = form.cleaned_data['password2']
email = form.cleaned_data['email'].strip() or ''
errormsg = 'Username "%s" is taken'
# check that username not taken
userslug = slugify(username)
Profile = get_profile_model(raise_on_error=False)
if Profile.objects.filter(slug=userslug).count():
# error!
safe_username = slugify('%s-%s' % (username, str(tznow())))
changed_warningmsg = errormsg + ", changed it to '%s'."
messages.warning(request, changed_warningmsg % (username, safe_username))
username = safe_username
# make user
try:
user = make_user(username, password, email=email, request=request)
except NanoUserExistsError:
next_profile = Profile.objects.get(user=user).get_absolute_url()
return HttpResponseRedirect(next_profile)
else:
# fake authentication, avoid a db-lookup/thread-trouble/
# race conditions
user.backend = 'django.contrib.auth.backends.ModelBackend'
_LOG.debug('Attempting login of: %s' % user)
login(request, user)
nexthop = getattr(settings, 'NANO_USER_SIGNUP_NEXT', reverse('nano_user_signup_done'))
try:
nexthop_profile = Profile.objects.get(user=user).get_absolute_url()
return HttpResponseRedirect(nexthop_profile)
except Profile.DoesNotExist:
pass
return HttpResponseRedirect(nexthop)
_LOG.debug('Should never end up here')
return render(request, template_name, data)
@login_required
def password_change(request, *args, **kwargs):
error = pop_error(request)
template_name = 'password_change_form.html'
if request.method == "POST":
form = PasswordChangeForm(request.POST)
if form.is_valid():
password = form.cleaned_data['password2']
user = request.user
user.set_password(password)
user.save()
request.session['error'] = None
return HttpResponseRedirect('/password/change/done/')
else:
form = PasswordChangeForm()
data = { 'form': form,
'error': error,}
return render(request, template_name, data)
def password_reset(request, project_name='Nano', *args, **kwargs):
User = get_user_model()
error = pop_error(request)
template = 'password_reset_form.html'
e_template = 'password_reset.txt'
help_message = None
e_subject = '%s password assistance' % project_name
e_message = """Your new password is:
%%s
It is long deliberately, so change it to
something you'll be able to remember.
%s' little password-bot
""" % project_name
e_from = getattr(settings, 'NANO_USER_EMAIL_SENDER', '')
form = PasswordResetForm()
if e_from and request.method == 'POST':
form = PasswordResetForm(request.POST)
if form.is_valid():
user = get_object_or_404(User, username=form.cleaned_data['username'])
if user.email:
tmp_pwd = random_password()
user.set_password(tmp_pwd)
result = send_mail(subject=e_subject, from_email=e_from, message=e_message % tmp_pwd, recipient_list=(user.email,))
user.save()
request.session['error'] = None
return HttpResponseRedirect('/password/reset/sent/')
else:
error = """There's no email-address registered for '%s',
the password can't be reset.""" % user.username
request.session['error'] = error
data = {'form': form,
'help_message': help_message,
'error':error}
return render(request, template, data)