Add password reset mutations

This commit is contained in:
Christian Cueni 2019-10-02 10:30:04 +02:00
parent 7d6a03743c
commit 46518a22f8
1 changed files with 96 additions and 2 deletions

View File

@ -9,14 +9,19 @@
# @author: chrigu <christian.cueni@iterativ.ch> # @author: chrigu <christian.cueni@iterativ.ch>
import graphene import graphene
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.views import PasswordResetView, PasswordResetConfirmView, INTERNAL_RESET_URL_TOKEN
from graphene import relay from graphene import relay
from core import settings
from users.models import User
class FieldError(graphene.ObjectType): class FieldError(graphene.ObjectType):
code = graphene.String() code = graphene.String()
class UpdateError(graphene.ObjectType): class MutationError(graphene.ObjectType):
field = graphene.String() field = graphene.String()
errors = graphene.List(FieldError) errors = graphene.List(FieldError)
@ -27,7 +32,7 @@ class Login(relay.ClientIDMutation):
password_input = graphene.String() password_input = graphene.String()
success = graphene.Boolean() success = graphene.Boolean()
errors = graphene.List(UpdateError) # todo: change for consistency errors = graphene.List(MutationError) # todo: change for consistency
@classmethod @classmethod
def mutate_and_get_payload(cls, root, info, **kwargs): def mutate_and_get_payload(cls, root, info, **kwargs):
@ -40,7 +45,96 @@ class Login(relay.ClientIDMutation):
return cls(success=False, errors=['invalid_credentials']) return cls(success=False, errors=['invalid_credentials'])
class PasswordReset(relay.ClientIDMutation):
class Input:
email_input = graphene.String()
success = graphene.Boolean()
errors = graphene.List(MutationError)
@classmethod
def mutate_and_get_payload(cls, root, info, **kwargs):
email = kwargs.get('email_input')
try:
user = User.objects.get(email=email) # todo: make lowercase
except User.DoesNotExist:
return cls(success=False, errors=['invalid_email'])
try:
password_reset_view = PasswordResetView(request=info.context)
form = password_reset_view.form_class({'email': user.email})
form.is_valid()
password_reset_view.form_valid(form)
except Exception:
return cls(success=False, errors=['email_error'])
return cls(success=True, errors=[])
class PasswordConfirm:
@classmethod
def verify_token_and_uidb64(cls, token, uidb64, request):
password_reset_confirm_view = PasswordResetConfirmView(request=request)
return password_reset_confirm_view.dispatch(uidb64=uidb64, token=token, request=request)
class PasswordResetVerify(relay.ClientIDMutation, PasswordConfirm):
class Input:
token_input = graphene.String()
uidb64_input = graphene.String()
success = graphene.Boolean()
errors = graphene.List(MutationError)
@classmethod
def mutate_and_get_payload(cls, root, info, **kwargs):
uidb64 = kwargs.get('uidb64_input')
token = kwargs.get('token_input')
http_response = cls.verify_token_and_uidb64(token, uidb64, info.context)
# PasswordResetConfirmView returns a webpage if either token or uidb64 are invalid (HTTP 200)
# if token and uidb64 are correct a redirect is returned (HTTP302)
if http_response.status_code == 302:
return cls(success=True, errors=[])
else:
return cls(success=False, errors=['invalid_challenge'])
class PasswordResetSetPassword(relay.ClientIDMutation, PasswordConfirm):
class Input:
new_password_input = graphene.String()
confirm_new_password_input = graphene.String()
uidb64_input = graphene.String()
success = graphene.Boolean()
errors = graphene.List(MutationError)
@classmethod
def mutate_and_get_payload(cls, root, info, **kwargs):
uidb64 = kwargs.get('uidb64_input')
new_password = kwargs.get('new_password_input')
confirm_new_password_input = kwargs.get('confirm_new_password_input')
# fake ordinary POST for view
info.context.POST = {
'new_password1': new_password,
'new_password2': confirm_new_password_input
}
http_response = cls.verify_token_and_uidb64(INTERNAL_RESET_URL_TOKEN, uidb64, info.context)
if http_response.status_code == 302:
return cls(success=True, errors=[])
else:
return cls(success=False, errors=['invalid_passwords']) # todo: check error from form
class UserMutations: class UserMutations:
login = Login.Field() login = Login.Field()
password_reset = PasswordReset.Field()
password_reset_verify = PasswordResetVerify.Field()
password_reset_set_password = PasswordResetSetPassword.Field()