Add password reset mutations
This commit is contained in:
parent
7d6a03743c
commit
46518a22f8
|
|
@ -9,14 +9,19 @@
|
|||
# @author: chrigu <christian.cueni@iterativ.ch>
|
||||
import graphene
|
||||
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 core import settings
|
||||
from users.models import User
|
||||
|
||||
|
||||
class FieldError(graphene.ObjectType):
|
||||
code = graphene.String()
|
||||
|
||||
|
||||
class UpdateError(graphene.ObjectType):
|
||||
class MutationError(graphene.ObjectType):
|
||||
field = graphene.String()
|
||||
errors = graphene.List(FieldError)
|
||||
|
||||
|
|
@ -27,7 +32,7 @@ class Login(relay.ClientIDMutation):
|
|||
password_input = graphene.String()
|
||||
|
||||
success = graphene.Boolean()
|
||||
errors = graphene.List(UpdateError) # todo: change for consistency
|
||||
errors = graphene.List(MutationError) # todo: change for consistency
|
||||
|
||||
@classmethod
|
||||
def mutate_and_get_payload(cls, root, info, **kwargs):
|
||||
|
|
@ -40,7 +45,96 @@ class Login(relay.ClientIDMutation):
|
|||
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:
|
||||
login = Login.Field()
|
||||
password_reset = PasswordReset.Field()
|
||||
password_reset_verify = PasswordResetVerify.Field()
|
||||
password_reset_set_password = PasswordResetSetPassword.Field()
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue