Пример #1
0
def forgot_password(request):
    """Form for requesting a PasswordResetToken for a specified account.
    Accepts email or username. Keeps for each user at most one token at a time 
    in the database. Also, it saves FakeTokens to obfuscate an account's existence
    whilst at the same time forcing a 5 minutes gap between the sending of two
    tokens for the same account."""
    
    if request.user.is_authenticated():
        return not_logged_out_routine(request)
    
    if request.method == 'POST':
        
        form = ForgotPasswordForm(request.POST)
        if form.is_valid():
            
            identifier = form.cleaned_data['identifier']
            
            user = None # do we need this here? -- Probably.
            
            try:
                
                # Form input could be an email or a username
                if looks_like_email(identifier):
                    user = CustomUser.objects.get(email=identifier)
                else:
                    user = CustomUser.objects.get(username=identifier)
                
                # At this point, we do have a user object.
                
                try:
                    # Between sending two tokens for the same user, a certain period should pass (--> settings)
                    previous_token = PasswordResetToken.objects.get(user=user)
                    if previous_token.blocks_new():
                        messages.error(request, 'You need to wait between sending two tokens for the same account.')
                        return redirect('accounts:forgot_password')
                    
                    # Only one token per user in the database; and we are about to create a new one.
                    else:
                        previous_token.delete()

                except PasswordResetToken.DoesNotExist:
                    # Fair enough.
                    pass
                
                # Alright, create the new token and send it.

                token = PasswordResetToken(user=user)
                token.save()
                request.session['token_value'] = token.value

                # EXTEND: send email

            except CustomUser.DoesNotExist:
                # No such user, therefor no email or token. But we do want a FakeToken.
                # See models.FakeToken or the docstring here for explanation why we do this FakeToken thing.
                try:
                    # Clear all previous FakeTokens.
                    
                    # No difference between email or username here:
                    previous_token = FakeToken.objects.get(user_identifier=identifier)
                    if previous_token.blocks_new() == True:
                        messages.error(request, 'You need to wait between sending two tokens for the same account.')
                        return redirect('accounts:forgot_password')
                    else:
                        previous_token.delete()

                except FakeToken.DoesNotExist:
                    pass
                
                ft = FakeToken(user_identifier=identifier)
                ft.save()
                request.session['token_value'] = None
            
            # we want to tell the user whether he had stated a username or an
            # email address; and we want to tell him which of both he stated
            if looks_like_email(identifier):
                request.session['token_email'] = identifier
                request.session['token_username'] = None
            else:
                request.session['token_email'] = None
                request.session['token_username'] = identifier

            return redirect('accounts:token_sent')
    
    else:
        form = ForgotPasswordForm
    
    return render(request, 'accounts/forgot_password.html', {
        'form':form
    })