''' class views for password management ''' from django.contrib.auth import login from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.shortcuts import redirect from django.template.response import TemplateResponse from django.utils.decorators import method_decorator from django.views import View from bookwyrm import models from bookwyrm.emailing import password_reset_email # pylint: disable= no-self-use class PasswordResetRequest(View): ''' forgot password flow ''' def get(self, request): ''' password reset page ''' return TemplateResponse( request, 'password_reset_request.html', {'title': 'Reset Password'} ) def post(self, request): ''' create a password reset token ''' email = request.POST.get('email') try: user = models.User.objects.get(email=email) except models.User.DoesNotExist: return redirect('/password-reset') # remove any existing password reset cods for this user models.PasswordReset.objects.filter(user=user).all().delete() # create a new reset code code = models.PasswordReset.objects.create(user=user) password_reset_email(code) data = {'message': 'Password reset link sent to %s' % email} return TemplateResponse(request, 'password_reset_request.html', data) class PasswordReset(View): ''' set new password ''' def get(self, request, code): ''' endpoint for sending invites ''' if request.user.is_authenticated: return redirect('/') try: reset_code = models.PasswordReset.objects.get(code=code) if not reset_code.valid(): raise PermissionDenied except models.PasswordReset.DoesNotExist: raise PermissionDenied return TemplateResponse( request, 'password_reset.html', {'title': 'Reset Password', 'code': reset_code.code} ) def post(self, request, code): ''' allow a user to change their password through an emailed token ''' try: reset_code = models.PasswordReset.objects.get( code=code ) except models.PasswordReset.DoesNotExist: data = {'errors': ['Invalid password reset link']} return TemplateResponse(request, 'password_reset.html', data) user = reset_code.user new_password = request.POST.get('password') confirm_password = request.POST.get('confirm-password') if new_password != confirm_password: data = {'errors': ['Passwords do not match']} return TemplateResponse(request, 'password_reset.html', data) user.set_password(new_password) user.save() login(request, user) reset_code.delete() return redirect('/') @method_decorator(login_required, name='dispatch') class ChangePassword(View): ''' change password as logged in user ''' def get(self, request): ''' change password page ''' data = { 'title': 'Change Password', 'user': request.user, } return TemplateResponse( request, 'preferences/change_password.html', data) def post(self, request): ''' allow a user to change their password ''' new_password = request.POST.get('password') confirm_password = request.POST.get('confirm-password') if new_password != confirm_password: return redirect('preferences/password') request.user.set_password(new_password) request.user.save() login(request, request.user) return redirect(request.user.local_path)