Add password reset mutations
This commit is contained in:
parent
7d6a03743c
commit
46518a22f8
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue