diff --git a/users/urls.py b/users/urls.py index 1fbc42b6..af1e0299 100644 --- a/users/urls.py +++ b/users/urls.py @@ -1,15 +1,15 @@ from django.urls import path, re_path from users.views import ( + CurrentUser, EmailResetPassword, ResetPassword, SpecialistsList, - UserAdditionalRolesView, + UserAdditionalRoles, UserDetail, UserList, - UserTypesView, - VerifyEmail, UserTypes, + VerifyEmail, ) app_name = "users" @@ -19,11 +19,11 @@ "specialists/", SpecialistsList.as_view() ), # this url actually returns mentors, experts and investors path("users/", UserList.as_view()), - path("users/roles/", UserAdditionalRolesView.as_view()), - path("users/types/", UserTypesView.as_view()), + path("users/roles/", UserAdditionalRoles.as_view()), + path("users/types/", UserTypes.as_view()), path("users//", UserDetail.as_view()), path("users/reset-password/", EmailResetPassword.as_view()), - path("users/user-types", UserTypes.as_view()), + path("users/current/", CurrentUser.as_view()), re_path( r"^account-confirm-email/", VerifyEmail.as_view(), diff --git a/users/views.py b/users/views.py index 0efa320d..3d19a7fe 100644 --- a/users/views.py +++ b/users/views.py @@ -19,11 +19,11 @@ from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework_simplejwt.tokens import RefreshToken +from rest_framework_simplejwt.tokens import RefreshToken, TokenError from core.permissions import IsOwnerOrReadOnly from core.utils import Email -from users.helpers import VERBOSE_ROLE_TYPES, VERBOSE_USER_TYPES +from users.helpers import VERBOSE_ROLE_TYPES from users.serializers import ( EmailSerializer, PasswordSerializer, @@ -73,17 +73,7 @@ def post(self, request, *args, **kwargs): return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) -class UserTypesView(GenericAPIView): - permission_classes = [AllowAny] - - def get(self, request, format=None): - """ - Return a tuple of user types. - """ - return Response(VERBOSE_USER_TYPES, status=status.HTTP_200_OK) - - -class UserAdditionalRolesView(GenericAPIView): +class UserAdditionalRoles(GenericAPIView): permission_classes = [AllowAny] def get(self, request, format=None): @@ -111,6 +101,17 @@ class UserDetail(RetrieveUpdateDestroyAPIView): serializer_class = UserDetailSerializer +class CurrentUser(APIView): + queryset = User.objects.get_users_for_detail_view() + permission_classes = [IsAuthenticated] + serializer_class = UserDetailSerializer + + def get(self, request): + user = request.user + serializer = UserDetailSerializer(user) + return Response(serializer.data, status=status.HTTP_200_OK) + + class UserTypes(APIView): def get(self, request, format=None): """ @@ -145,13 +146,13 @@ def get(self, request): except jwt.ExpiredSignatureError: return redirect( REDIRECT_URL, - status=status.HTTP_200_OK, + status=status.HTTP_400_BAD_REQUEST, message="Activate Expired", ) except jwt.DecodeError: return redirect( REDIRECT_URL, - status=status.HTTP_200_OK, + status=status.HTTP_400_BAD_REQUEST, message="Decode error", ) @@ -166,20 +167,26 @@ def post(self, request, *args, **kwargs): user = User.objects.get(email=serializer.data["email"]) - token = RefreshToken.for_user(user).access_token + access_token = RefreshToken.for_user(user).access_token + refresh_token = RefreshToken.for_user(user) relative_link = reverse("users:password_reset_sent") current_site = get_current_site(request).domain - absolute_url = "http://" + current_site + relative_link + "?token=" + str(token) + absolute_url = ( + "http://" + + current_site + + relative_link + + f"?access_token={access_token}&refresh_token={refresh_token}" + ) - email_body = "Hi, {} {}! Use link below verify your email {}".format( + email_body = "Hi, {} {}! Use link below for reset password {}".format( user.first_name, user.last_name, absolute_url ) data = { "email_body": email_body, - "email_subject": "Verify your email", + "email_subject": "Reset password", "to_email": user.email, } @@ -192,24 +199,43 @@ class ResetPassword(UpdateAPIView): serializer_class = PasswordSerializer permission_classes = [AllowAny] + def get(self, request, *args, **kwargs): + refresh_token = request.GET.get("refresh_token") + try: + RefreshToken(refresh_token).check_blacklist() + except TokenError: + return redirect( + "https://procollab.ru/auth/reset_password/", + status=status.HTTP_400_BAD_REQUEST, + message="Used token", + ) + + return Response({"message": "Enter new password"}) + def update(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid() try: - token = request.GET.get("token") - payload = jwt.decode(jwt=token, key=settings.SECRET_KEY, algorithms=["HS256"]) + refresh_token = request.GET.get("refresh_token") + access_token = request.GET.get("access_token") + payload = jwt.decode( + jwt=access_token, key=settings.SECRET_KEY, algorithms=["HS256"] + ) user = User.objects.get(id=payload["user_id"]) - last_update = user.datatime_updated - if (datetime.now().minute - last_update.minute) <= 10: - return Response( - {"response": "You can't change your password so often"}, - status=status.HTTP_200_OK, + last_update = user.datetime_updated + frequency_update = datetime.utcnow().minute - last_update.minute + if frequency_update <= 10: + return redirect( + "https://procollab.ru/auth/reset_password/", + status=status.HTTP_400_BAD_REQUEST, + message="You can't change your password so often", ) user.set_password(serializer.data["new_password"]) user.save() + RefreshToken(refresh_token).blacklist() return redirect( "https://procollab.ru/auth/reset_password/", status=status.HTTP_200_OK, @@ -219,12 +245,12 @@ def update(self, request, *args, **kwargs): except jwt.ExpiredSignatureError: return redirect( "https://procollab.ru/auth/reset_password/", - status=status.HTTP_200_OK, + status=status.HTTP_400_BAD_REQUEST, message="Activate Expired", ) except jwt.DecodeError: return redirect( "https://procollab.ru/auth/reset_password/", - status=status.HTTP_200_OK, + status=status.HTTP_400_BAD_REQUEST, message="Decode error", )