diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index b6de5bb0..bd28cb88 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -21,7 +21,6 @@ class UserSerializer(serializers.ModelSerializer): # REQUEST username = serializers.CharField( validators=(rest_validators.UniqueValidator(queryset=models.User.objects.all()),), - write_only=True, required=False) first_name = serializers.CharField(required=False, write_only=True) last_name = serializers.CharField(required=False, write_only=True) diff --git a/apps/account/serializers/web.py b/apps/account/serializers/web.py index cee66bfa..60a68820 100644 --- a/apps/account/serializers/web.py +++ b/apps/account/serializers/web.py @@ -7,6 +7,7 @@ from rest_framework import serializers from account import models, tasks from utils import exceptions as utils_exceptions +from utils.methods import username_validator class PasswordResetSerializer(serializers.ModelSerializer): @@ -28,14 +29,15 @@ class PasswordResetSerializer(serializers.ModelSerializer): if user.is_anonymous: username_or_email = attrs.get('username_or_email') if not username_or_email: - raise serializers.ValidationError(_('Username or Email not requested')) + raise serializers.ValidationError(_('Username or Email not in request body.')) # Check user in DB + username_or_email = (username_or_email.lower() + if username_validator(username_or_email) is False + else username_or_email) user_qs = models.User.objects.filter(Q(email=username_or_email) | Q(username=username_or_email)) if user_qs.exists(): attrs['user'] = user_qs.first() - else: - raise utils_exceptions.UserNotFoundError() else: attrs['user'] = user return attrs @@ -48,8 +50,7 @@ class PasswordResetSerializer(serializers.ModelSerializer): obj = models.ResetPasswordToken.objects.create( user=user, ip_address=ip_address, - source=models.ResetPasswordToken.WEB - ) + source=models.ResetPasswordToken.WEB) if settings.USE_CELERY: tasks.send_reset_password_email.delay(obj.id) else: diff --git a/apps/account/views/web.py b/apps/account/views/web.py index af147ba6..4f10ccc2 100644 --- a/apps/account/views/web.py +++ b/apps/account/views/web.py @@ -22,16 +22,23 @@ from account.forms import SetPasswordForm from account.serializers import web as serializers from utils import exceptions as utils_exceptions from utils.models import GMTokenGenerator -from utils.views import (JWTCreateAPIView, - JWTGenericViewMixin) +from utils.views import JWTGenericViewMixin -class PasswordResetView(JWTCreateAPIView): +class PasswordResetView(JWTGenericViewMixin): """View for resetting user password""" permission_classes = (permissions.AllowAny, ) serializer_class = serializers.PasswordResetSerializer queryset = models.ResetPasswordToken.objects.valid() + def post(self, request, *args, **kwargs): + """Override create method""" + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + if serializer.validated_data.get('user'): + serializer.save() + return Response(status=status.HTTP_200_OK) + class PasswordResetConfirmView(JWTGenericViewMixin): """View for confirmation new password""" diff --git a/apps/authorization/serializers/common.py b/apps/authorization/serializers/common.py index 5817e191..f5e24fc9 100644 --- a/apps/authorization/serializers/common.py +++ b/apps/authorization/serializers/common.py @@ -58,7 +58,7 @@ class SignupSerializer(serializers.ModelSerializer): obj = account_models.User.objects.make( username=validated_data.get('username'), password=validated_data.get('password'), - email=validated_data.get('email'), + email=validated_data.get('email').lower(), newsletter=validated_data.get('newsletter')) # Send verification link on user email if settings.USE_CELERY: diff --git a/apps/utils/views.py b/apps/utils/views.py index d01d30cd..d129fb73 100644 --- a/apps/utils/views.py +++ b/apps/utils/views.py @@ -16,6 +16,13 @@ class JWTGenericViewMixin(generics.GenericAPIView): REFRESH_TOKEN_HTTP_ONLY = False REFRESH_TOKEN_SECURE = False + + LOCALE_HTTP_ONLY = False + LOCALE_SECURE = False + + COUNTRY_CODE_HTTP_ONLY = False + COUNTRY_CODE_SECURE = False + COOKIE = namedtuple('COOKIE', ['key', 'value', 'http_only', 'secure', 'max_age']) def _put_data_in_cookies(self, @@ -26,21 +33,32 @@ class JWTGenericViewMixin(generics.GenericAPIView): cookies it is list that contain namedtuples cookies would contain key, value and secure parameters. """ - COOKIES = list() + COOKIES = [] - # Write to cookie access and refresh token with secure flag - if access_token and refresh_token: - _access_token = self.COOKIE(key='access_token', - value=access_token, - http_only=self.ACCESS_TOKEN_HTTP_ONLY, - secure=self.ACCESS_TOKEN_SECURE, - max_age=settings.COOKIES_MAX_AGE if permanent else None) - _refresh_token = self.COOKIE(key='refresh_token', - value=refresh_token, - http_only=self.REFRESH_TOKEN_HTTP_ONLY, - secure=self.REFRESH_TOKEN_SECURE, - max_age=settings.COOKIES_MAX_AGE if permanent else None) - COOKIES.extend((_access_token, _refresh_token)) + if hasattr(self.request, 'locale'): + COOKIES.append(self.COOKIE(key='locale', + value=self.request.locale, + http_only=self.ACCESS_TOKEN_HTTP_ONLY, + secure=self.LOCALE_SECURE, + max_age=settings.COOKIES_MAX_AGE if permanent else None)) + if hasattr(self.request, 'country_code'): + COOKIES.append(self.COOKIE(key='country_code', + value=self.request.country_code, + http_only=self.COUNTRY_CODE_HTTP_ONLY, + secure=self.COUNTRY_CODE_SECURE, + max_age=settings.COOKIES_MAX_AGE if permanent else None)) + if access_token: + COOKIES.append(self.COOKIE(key='access_token', + value=access_token, + http_only=self.ACCESS_TOKEN_HTTP_ONLY, + secure=self.ACCESS_TOKEN_SECURE, + max_age=settings.COOKIES_MAX_AGE if permanent else None)) + if refresh_token: + COOKIES.append(self.COOKIE(key='refresh_token', + value=refresh_token, + http_only=self.REFRESH_TOKEN_HTTP_ONLY, + secure=self.REFRESH_TOKEN_SECURE, + max_age=settings.COOKIES_MAX_AGE if permanent else None)) return COOKIES def _put_cookies_in_response(self, cookies: list, response: Response):