""" 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_lazy 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.viewer_aware_objects(request.user).get( email=email, email__isnull=False ) 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": _(f"A password reset link sent to {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, update_fields=["password"]) 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, update_fields=["password"]) login(request, request.user) return redirect(request.user.local_path)