Commit 9bd8c31d05d30e57cdb557c424557af104fcef23
Exists in
master
Merge branch 'master' of git.ucsd.edu:110swag/flashy-backend
Showing 2 changed files Side-by-side Diff
flashcards/api.py
View file @
9bd8c31
1 | 1 | from django.contrib.auth import login, authenticate |
2 | 2 | from django.core.mail import send_mail |
3 | +from django.contrib.auth import authenticate, login | |
4 | +from django.contrib.auth.tokens import default_token_generator | |
3 | 5 | from rest_framework.views import APIView |
4 | 6 | from rest_framework.response import Response |
5 | 7 | from rest_framework import status |
6 | -from rest_framework.exceptions import ValidationError | |
8 | +from rest_framework.exceptions import ValidationError, NotFound | |
7 | 9 | from flashcards.serializers import * |
8 | 10 | |
9 | 11 | |
... | ... | @@ -60,4 +62,84 @@ |
60 | 62 | login(request, user) |
61 | 63 | |
62 | 64 | return Response(UserSerializer(User).data) |
65 | + | |
66 | + def delete(self, request, format=None): | |
67 | + request.user.delete() | |
68 | + return Response(status=status.HTTP_204_NO_CONTENT) | |
69 | + | |
70 | +class UserLogin(APIView): | |
71 | + """ | |
72 | + Authenticates user and returns user data if valid. Handles invalid | |
73 | + users. | |
74 | + """ | |
75 | + def post(self, request, format=None): | |
76 | + """ | |
77 | + Returns user data if valid. | |
78 | + """ | |
79 | + if 'email' not in request.data: | |
80 | + raise ValidationError('Email is required') | |
81 | + if 'password' not in request.data: | |
82 | + raise ValidationError('Password is required') | |
83 | + | |
84 | + email = request.data['email'] | |
85 | + password = request.data['password'] | |
86 | + user = authenticate(username=email, password=password) | |
87 | + | |
88 | + if user is not None: | |
89 | + if user.is_active: | |
90 | + login(request, user) | |
91 | + return Response(UserSerializer(User).data) | |
92 | + else: | |
93 | + raise ValidationError('Account is disabled') | |
94 | + else: | |
95 | + raise ValidationError('Invalid email or password') | |
96 | + | |
97 | +class PasswordReset(APIView): | |
98 | + """ | |
99 | + Allows user to reset their password. | |
100 | + """ | |
101 | + def post(self, request, format=None): | |
102 | + """ | |
103 | + Send a password reset token/link to the provided email. | |
104 | + """ | |
105 | + if 'email' not in request.data: | |
106 | + raise ValidationError('Email is required') | |
107 | + | |
108 | + email = request.data['email'] | |
109 | + | |
110 | + # Find the user since they are not logged in. | |
111 | + try: | |
112 | + user = User.objects.get(email=email) | |
113 | + except User.DoesNotExist: | |
114 | + raise NotFound('Email does not exist') | |
115 | + | |
116 | + token = default_token_generator.make_token(user) | |
117 | + | |
118 | + body = ''' | |
119 | + Visit the following link to reset your password: | |
120 | + http://flashy.cards/app/reset_password/%d/%s | |
121 | + | |
122 | + If you did not request a password reset, no action is required. | |
123 | + ''' | |
124 | + | |
125 | + send_mail("Please verify your Flashy account", | |
126 | + body % (user.pk, token), | |
127 | + "noreply@flashy.cards", | |
128 | + [user.email]) | |
129 | + | |
130 | + def patch(self, request, format=None): | |
131 | + """ | |
132 | + Updates user's password to new password. | |
133 | + """ | |
134 | + if 'new_password' not in request.data: | |
135 | + raise ValidationError('New password is required') | |
136 | + if not request.data['new_password']: | |
137 | + raise ValidationError('Password cannot be blank') | |
138 | + | |
139 | + user = request.user | |
140 | + | |
141 | + user.set_password(request.data['new_password']) | |
142 | + user.save() | |
143 | + | |
144 | + return Response(status=status.HTTP_204_NO_CONTENT) |
flashy/urls.py
View file @
9bd8c31
... | ... | @@ -9,7 +9,9 @@ |
9 | 9 | router.register(r'lectureperiods', LecturePeriodViewSet) |
10 | 10 | |
11 | 11 | urlpatterns = [ |
12 | - url(r'^api/user/me$', UserDetail.as_view()), | |
12 | + url(r'^api/users/me$', UserDetail.as_view()), | |
13 | + url(r'^api/login$', UserLogin.as_view()), | |
14 | + url(r'^api/reset_password$', PasswordReset.as_view()), | |
13 | 15 | url(r'^api/', include(router.urls)), |
14 | 16 | url(r'^admin/doc/', include('django.contrib.admindocs.urls')), |
15 | 17 | url(r'^admin/', include(admin.site.urls)), |