Skip to content

Commit 0aaf118

Browse files
refactor: Simplify validate method in SignInSerializer.
1 parent ac140c2 commit 0aaf118

File tree

3 files changed

+40
-68
lines changed

3 files changed

+40
-68
lines changed

promo_code/user/serializers.py

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,26 @@ class SignInSerializer(
8282
write_only=True,
8383
)
8484

85-
def validate(self, data):
86-
email = data.get('email')
87-
password = data.get('password')
85+
def validate(self, attrs):
86+
user = self.authenticate_user(attrs)
87+
88+
self.update_token_version(user)
89+
90+
data = super().validate(attrs)
91+
92+
refresh = rest_framework_simplejwt.tokens.RefreshToken(data['refresh'])
93+
94+
self.invalidate_previous_tokens(user, refresh['jti'])
95+
96+
return data
97+
98+
def authenticate_user(self, attrs):
99+
email = attrs.get('email')
100+
password = attrs.get('password')
88101

89102
if not email or not password:
90-
raise rest_framework.serializers.ValidationError(
91-
{'status': 'error', 'message': 'Both fields are required.'},
103+
raise rest_framework.exceptions.ValidationError(
104+
{'detail': 'Both email and password are required'},
92105
code='required',
93106
)
94107

@@ -97,55 +110,26 @@ def validate(self, data):
97110
email=email,
98111
password=password,
99112
)
100-
if not user:
101-
raise rest_framework.exceptions.AuthenticationFailed(
102-
{'status': 'error', 'message': 'Invalid email or password.'},
103-
code='authorization',
104-
)
105113

106-
authenticate_kwargs = {
107-
self.username_field: data[self.username_field],
108-
'password': data['password'],
109-
}
110-
try:
111-
authenticate_kwargs['request'] = self.context['request']
112-
except KeyError:
113-
pass
114-
115-
self.user = django.contrib.auth.authenticate(**authenticate_kwargs)
116-
117-
if not getattr(self.user, 'is_active', None):
114+
if not user or not user.is_active:
118115
raise rest_framework.exceptions.AuthenticationFailed(
119-
self.error_messages['no_active_account'],
120-
'no_active_account',
116+
{'detail': 'Invalid credentials or inactive account'},
117+
code='authentication_failed',
121118
)
122119

123-
self.user.token_version += 1
124-
self.user.save()
120+
return user
125121

126-
refresh = self.get_token(self.user)
127-
data = {
128-
'refresh': str(refresh),
129-
'access': str(refresh.access_token),
130-
}
131-
132-
current_jti = refresh['jti']
133-
134-
tokens_qs = tb_models.OutstandingToken.objects.filter(
135-
user=self.user,
136-
)
137-
138-
outstanding_tokens = tokens_qs.exclude(jti=current_jti)
122+
def invalidate_previous_tokens(self, user, current_jti):
123+
outstanding_tokens = tb_models.OutstandingToken.objects.filter(
124+
user=user,
125+
).exclude(jti=current_jti)
139126

140127
for token in outstanding_tokens:
141-
(
142-
tb_models.BlacklistedToken.objects.get_or_create(
143-
token=token,
144-
)
145-
)
128+
tb_models.BlacklistedToken.objects.get_or_create(token=token)
146129

147-
data['token_version'] = self.user.token_version
148-
return data
130+
def update_token_version(self, user):
131+
user.token_version += 1
132+
user.save()
149133

150134
def get_token(self, user):
151135
token = super().get_token(user)

promo_code/user/tests.py

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -470,12 +470,12 @@ def test_registration_token_invalid_after_login(self):
470470
self.assertEqual(response.status_code, 200)
471471

472472
def test_refresh_token_invalidation_after_new_login(self):
473-
474473
first_login_response = self.client.post(
475474
self.signin_url,
476475
self.user_data,
477476
format='json',
478477
)
478+
479479
refresh_token_v1 = first_login_response.data['refresh']
480480

481481
second_login_response = self.client.post(
@@ -534,21 +534,3 @@ def test_blacklist_storage(self):
534534
(tb_models.OutstandingToken.objects.count()),
535535
2,
536536
)
537-
538-
def test_token_version_increment(self):
539-
response1 = self.client.post(
540-
self.signin_url,
541-
self.user_data,
542-
format='json',
543-
)
544-
self.assertEqual(response1.data['token_version'], 1)
545-
546-
response2 = self.client.post(
547-
self.signin_url,
548-
self.user_data,
549-
format='json',
550-
)
551-
self.assertEqual(response2.data['token_version'], 2)
552-
553-
user_ = user.models.User.objects.get(email=self.user_data['email'])
554-
self.assertEqual(user_.token_version, 2)

promo_code/user/views.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ def create(self, request, *args, **kwargs):
3535
return self.handle_validation_error()
3636

3737
user = serializer.save()
38+
3839
refresh = rest_framework_simplejwt.tokens.RefreshToken.for_user(user)
3940
refresh['token_version'] = user.token_version
4041
access_token = refresh.access_token
42+
4143
return rest_framework.response.Response(
4244
{'access': str(access_token), 'refresh': str(refresh)},
4345
status=rest_framework.status.HTTP_200_OK,
@@ -51,11 +53,10 @@ class SignInView(
5153
serializer_class = user.serializers.SignInSerializer
5254

5355
def post(self, request, *args, **kwargs):
54-
serializer = self.get_serializer(data=request.data)
5556

5657
try:
58+
serializer = self.get_serializer(data=request.data)
5759
serializer.is_valid(raise_exception=True)
58-
response = super().post(request, *args, **kwargs)
5960
except (
6061
rest_framework.serializers.ValidationError,
6162
rest_framework_simplejwt.exceptions.TokenError,
@@ -65,7 +66,12 @@ def post(self, request, *args, **kwargs):
6566

6667
raise rest_framework_simplejwt.exceptions.InvalidToken(str(e))
6768

69+
response_data = {
70+
'access': serializer.validated_data['access'],
71+
'refresh': serializer.validated_data['refresh'],
72+
}
73+
6874
return rest_framework.response.Response(
69-
response,
75+
response_data,
7076
status=rest_framework.status.HTTP_200_OK,
7177
)

0 commit comments

Comments
 (0)