Commit fe546f43f2c7c9a1f7fafbaae9f59147d4506f79
1 parent
7a17fac38e
Exists in
master
move verify_email outside user update
Showing 5 changed files with 33 additions and 24 deletions Side-by-side Diff
flashcards/models.py
View file @
fe546f4
... | ... | @@ -143,7 +143,7 @@ |
143 | 143 | self.save() |
144 | 144 | |
145 | 145 | def by_retention(self, sections, material_date_begin, material_date_end): |
146 | - section_pks = map(lambda i: i['pk'], sections.values('pk')) | |
146 | + section_pks = sections.values_list('pk') | |
147 | 147 | user_flashcard_filter = UserFlashcard.objects.filter( |
148 | 148 | user=self, flashcard__section__pk__in=section_pks, |
149 | 149 | flashcard__material_date__gte=material_date_begin, |
flashcards/serializers.py
View file @
fe546f4
... | ... | @@ -46,23 +46,18 @@ |
46 | 46 | except User.DoesNotExist: |
47 | 47 | raise serializers.ValidationError('Could not verify reset token') |
48 | 48 | |
49 | +class EmailVerificationSerializer(Serializer): | |
50 | + confirmation_key = CharField() | |
49 | 51 | |
50 | 52 | class UserUpdateSerializer(Serializer): |
51 | 53 | old_password = CharField(required=False) |
52 | - new_password = CharField(required=False, allow_blank=False) | |
53 | - confirmation_key = CharField(required=False) | |
54 | + new_password = CharField(required=False, allow_blank=False)\ | |
54 | 55 | # reset_token = CharField(required=False) |
55 | 56 | |
56 | 57 | def validate(self, data): |
57 | 58 | if 'new_password' in data and 'old_password' not in data: |
58 | 59 | raise serializers.ValidationError('old_password is required to set a new_password') |
59 | 60 | return data |
60 | - | |
61 | - | |
62 | -# class Password(Serializer): | |
63 | -# email = EmailField(required=True) | |
64 | -# password = CharField(required=True) | |
65 | - | |
66 | 61 | |
67 | 62 | class LecturePeriodSerializer(ModelSerializer): |
68 | 63 | class Meta: |
flashcards/tests/test_api.py
View file @
fe546f4
... | ... | @@ -120,13 +120,13 @@ |
120 | 120 | |
121 | 121 | # try activating with an invalid key |
122 | 122 | |
123 | - url = '/api/me/' | |
124 | - response = self.client.patch(url, {'confirmation_key': 'NOT A KEY'}) | |
123 | + url = '/api/verify_email/' | |
124 | + response = self.client.post(url, {'confirmation_key': 'NOT A KEY'}) | |
125 | 125 | self.assertContains(response, 'confirmation_key is invalid', status_code=400) |
126 | 126 | |
127 | 127 | # try activating with the valid key |
128 | - response = self.client.patch(url, {'confirmation_key': user.confirmation_key}) | |
129 | - self.assertTrue(response.data['is_confirmed']) | |
128 | + response = self.client.post(url, {'confirmation_key': user.confirmation_key}) | |
129 | + self.assertContains(response, '', status_code=204) | |
130 | 130 | |
131 | 131 | |
132 | 132 | class ProfileViewTest(APITestCase): |
flashcards/views.py
View file @
fe546f4
... | ... | @@ -10,7 +10,7 @@ |
10 | 10 | from flashcards.serializers import SectionSerializer, UserUpdateSerializer, RegistrationSerializer, UserSerializer, \ |
11 | 11 | PasswordResetSerializer, PasswordResetRequestSerializer, EmailPasswordSerializer, FlashcardSerializer, \ |
12 | 12 | FlashcardUpdateSerializer, QuizRequestSerializer, QuizResponseSerializer, \ |
13 | - QuizAnswerRequestSerializer, DeepSectionSerializer | |
13 | + QuizAnswerRequestSerializer, DeepSectionSerializer, EmailVerificationSerializer | |
14 | 14 | from rest_framework.decorators import detail_route, permission_classes, api_view, list_route |
15 | 15 | from rest_framework.generics import ListAPIView, GenericAPIView |
16 | 16 | from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, UpdateModelMixin |
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | from rest_framework.response import Response |
24 | 24 | from rest_framework.exceptions import AuthenticationFailed, NotAuthenticated, ValidationError, PermissionDenied |
25 | 25 | from simple_email_confirmation import EmailAddress |
26 | +from simple_email_confirmation.models import EmailAddressManager | |
26 | 27 | |
27 | 28 | |
28 | 29 | def log_event(request, event=''): |
... | ... | @@ -144,7 +145,7 @@ |
144 | 145 | |
145 | 146 | def patch(self, request, format=None): |
146 | 147 | """ |
147 | - Updates the user's password, or verifies their email address | |
148 | + Updates the user's password | |
148 | 149 | --- |
149 | 150 | request_serializer: UserUpdateSerializer |
150 | 151 | response_serializer: UserSerializer |
... | ... | @@ -160,13 +161,6 @@ |
160 | 161 | request.user.save() |
161 | 162 | log_event(request, 'change password') |
162 | 163 | |
163 | - if 'confirmation_key' in data: | |
164 | - try: | |
165 | - request.user.confirm_email(data['confirmation_key']) | |
166 | - log_event(request, 'confirm email') | |
167 | - except EmailAddress.DoesNotExist: | |
168 | - raise ValidationError('confirmation_key is invalid') | |
169 | - | |
170 | 164 | return Response(UserSerializer(request.user).data) |
171 | 165 | |
172 | 166 | def get(self, request, format=None): |
173 | 167 | |
174 | 168 | |
... | ... | @@ -189,12 +183,31 @@ |
189 | 183 | return Response(status=HTTP_204_NO_CONTENT) |
190 | 184 | |
191 | 185 | |
192 | - | |
193 | 186 | @api_view(['POST']) |
194 | 187 | @permission_classes([IsAuthenticated]) |
195 | 188 | def resend_confirmation_email(request): |
189 | + "Resends a confirmation email to a user" | |
196 | 190 | request.user.send_confirmation_email() |
197 | 191 | return Response(status=HTTP_204_NO_CONTENT) |
192 | + | |
193 | + | |
194 | +@api_view(['POST']) | |
195 | +@permission_classes([IsAuthenticated]) | |
196 | +def verify_email(request): | |
197 | + """ | |
198 | + Accepts a user's email confirmation_key to verify their email address | |
199 | + --- | |
200 | + request_serializer: EmailVerificationSerializer | |
201 | + """ | |
202 | + try: | |
203 | + data = EmailVerificationSerializer(data=request.data) | |
204 | + data.is_valid(raise_exception=True) | |
205 | + email = EmailAddress.objects.confirm(data.validated_data['confirmation_key']) | |
206 | + log_event(request, 'confirm email' + str(email)) | |
207 | + return Response(status=HTTP_204_NO_CONTENT) | |
208 | + except EmailAddress.DoesNotExist: | |
209 | + raise ValidationError('confirmation_key is invalid') | |
210 | + | |
198 | 211 | |
199 | 212 | @api_view(['POST']) |
200 | 213 | def register(request, format=None): |
flashy/urls.py
View file @
fe546f4
1 | 1 | from django.conf.urls import include, url |
2 | 2 | from django.contrib import admin |
3 | 3 | from flashcards.views import SectionViewSet, UserDetail, FlashcardViewSet, UserSectionListView, request_password_reset, \ |
4 | - reset_password, logout, login, register, UserFlashcardQuizViewSet, resend_confirmation_email | |
4 | + reset_password, logout, login, register, UserFlashcardQuizViewSet, resend_confirmation_email, verify_email | |
5 | 5 | from flashy.frontend_serve import serve_with_default |
6 | 6 | from flashy.settings import DEBUG, IN_PRODUCTION |
7 | 7 | from rest_framework.routers import DefaultRouter |
... | ... | @@ -20,6 +20,7 @@ |
20 | 20 | url(r'^api/logout/$', logout), |
21 | 21 | url(r'^api/me/sections/', UserSectionListView.as_view()), |
22 | 22 | url(r'^api/resend_confirmation_email/', resend_confirmation_email), |
23 | + url(r'^api/verify_email/', verify_email), | |
23 | 24 | url(r'^api/request_password_reset/', request_password_reset), |
24 | 25 | url(r'^api/reset_password/', reset_password), |
25 | 26 | url(r'^api/', include(router.urls)), |