diff --git a/flashcards/api.py b/flashcards/api.py index 7c8fb8e..d9ef085 100644 --- a/flashcards/api.py +++ b/flashcards/api.py @@ -1,9 +1,10 @@ from django.core.mail import send_mail from django.contrib.auth import authenticate, login +from django.contrib.auth.tokens import default_token_generator from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status -from rest_framework.exceptions import ValidationError +from rest_framework.exceptions import ValidationError, NotFound from flashcards.serializers import * @@ -68,6 +69,9 @@ class UserLogin(APIView): users. """ def post(self, request, format=None): + """ + Returns user data if valid. + """ if 'email' not in request.data: raise ValidationError('Email is required') if 'password' not in request.data: @@ -85,3 +89,52 @@ class UserLogin(APIView): raise ValidationError('Account is disabled') else: raise ValidationError('Invalid email or password') + +class PasswordReset(APIView): + """ + Allows user to reset their password. + """ + def post(self, request, format=None): + """ + Send a password reset token/link to the provided email. + """ + if 'email' not in request.data: + raise ValidationError('Email is required') + + email = request.data['email'] + + # Find the user since they are not logged in. + try: + user = User.objects.get(email=email) + except User.DoesNotExist: + raise NotFound('Email does not exist') + + token = default_token_generator.make_token(user) + + body = ''' + Visit the following link to reset your password: + http://flashy.cards/app/reset_password/%d/%s + + If you did not request a password reset, no action is required. + ''' + + send_mail("Please verify your Flashy account", + body % (user.pk, token), + "noreply@flashy.cards", + [user.email]) + + def patch(self, request, format=None): + """ + Updates user's password to new password. + """ + if 'new_password' not in request.data: + raise ValidationError('New password is required') + if not request.data['new_password']: + raise ValidationError('Password cannot be blank') + + user = request.user + + user.set_password(request.data['new_password']) + user.save() + + return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/flashy/urls.py b/flashy/urls.py index 0e2a874..894c609 100644 --- a/flashy/urls.py +++ b/flashy/urls.py @@ -11,6 +11,7 @@ router.register(r'lectureperiods', LecturePeriodViewSet) urlpatterns = [ url(r'^api/users/me$', UserDetail.as_view()), url(r'^api/login$', UserLogin.as_view()), + url(r'^api/reset_password$', PasswordReset.as_view()), url(r'^api/', include(router.urls)), url(r'^admin/doc/', include('django.contrib.admindocs.urls')), url(r'^admin/', include(admin.site.urls)),