""" 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.utils.translation import gettext as _ 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", ) 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: data = {"error": _("No user with that email address was found.")} return TemplateResponse(request, "password_reset_request.html", data) # 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": _("A 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", {"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(broadcast=False) 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 = {"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(broadcast=False) login(request, request.user) return redirect(request.user.local_path)