From f84f03fd5b5a605a661aaa28f651c96fa9431416 Mon Sep 17 00:00:00 2001 From: i701 Date: Fri, 25 Jul 2025 10:12:04 +0500 Subject: [PATCH] =?UTF-8?q?feat(agreement):=20implement=20user=20agreement?= =?UTF-8?q?=20update=20functionality=20with=20validation=20checks=20?= =?UTF-8?q?=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/serializers.py | 9 ++++++++ api/urls.py | 6 ++++++ api/views.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/api/serializers.py b/api/serializers.py index e3b0c35..5bc09bc 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -49,6 +49,15 @@ class UserUpdateSerializer(serializers.ModelSerializer): ) +class UserAgreementSerializer(serializers.ModelSerializer): + """serializer for the user agreement object""" + + class Meta: # type: ignore + model = User + fields = ("agreement",) + extra_kwargs = {"agreement": {"required": True, "allow_null": False}} + + class CustomUserSerializer(serializers.ModelSerializer): """serializer for the user object""" diff --git a/api/urls.py b/api/urls.py index 7517049..f8c05b0 100644 --- a/api/urls.py +++ b/api/urls.py @@ -23,6 +23,7 @@ from .views import ( UserVerifyAPIView, UserUpdateAPIView, UserRejectAPIView, + AgreementUpdateAPIView, ) @@ -45,6 +46,11 @@ urlpatterns = [ path("users/temp/filter/", filter_temporary_user, name="filter-temporary-users"), # User verification flow path("users//verify/", UserVerifyAPIView.as_view(), name="user-verify"), + path( + "users//agreement/", + AgreementUpdateAPIView.as_view(), + name="user-agreement-update", + ), path("users//reject/", UserRejectAPIView.as_view(), name="user-reject"), path("healthcheck/", healthcheck, name="healthcheck"), path("test/", test_email, name="testemail"), diff --git a/api/views.py b/api/views.py index 12f5a08..1b26d7f 100644 --- a/api/views.py +++ b/api/views.py @@ -19,6 +19,7 @@ from api.serializers import ( OTPVerificationSerializer, TemporaryUserSerializer, UserUpdateSerializer, + UserAgreementSerializer, ) from django.shortcuts import get_object_or_404 from django.utils import timezone @@ -378,6 +379,57 @@ class UserUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView): return super().update(request, *args, **kwargs) +class AgreementUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView): + serializer_class = UserAgreementSerializer + queryset = User.objects.all() + lookup_field = "pk" + + def update(self, request, *args, **kwargs): + user_id = kwargs.get("pk") + user = get_object_or_404(User, pk=user_id) + if user.is_superuser: + return Response( + {"message": "You cannot update a superuser."}, + status=status.HTTP_403_FORBIDDEN, + ) + if request.user != user and ( + not request.user.is_authenticated + or not getattr(request.user, "is_admin", False) + ): + return Response( + {"message": "You are not authorized to update this user."}, + status=status.HTTP_403_FORBIDDEN, + ) + serializer = self.get_serializer( + user, + data=request.data, + partial=True, + ) + agreement = request.data.get("agreement") + if not agreement: + return Response( + {"message": "Agreement file is required."}, + status=status.HTTP_400_BAD_REQUEST, + ) + if agreement.size > 10 * 1024 * 1024: # 5 MB limit + return Response( + {"message": "File size exceeds 10 MB limit."}, + status=status.HTTP_400_BAD_REQUEST, + ) + if agreement.content_type not in [ + "application/pdf", + ]: + return Response( + {"message": "Invalid file type. Only PDF files are allowed."}, + status=status.HTTP_400_BAD_REQUEST, + ) + if agreement: + user.agreement = agreement + serializer.is_valid(raise_exception=True) + user.save() + return super().update(request, *args, **kwargs) + + class KnoxTokenListApiView( StaffEditorPermissionMixin, generics.ListAPIView,