diff --git a/apps/authentication/api/v1/serializers/serializer.py b/apps/authentication/api/v1/serializers/serializer.py index d77467a..bce393b 100644 --- a/apps/authentication/api/v1/serializers/serializer.py +++ b/apps/authentication/api/v1/serializers/serializer.py @@ -4,7 +4,8 @@ from django.contrib.auth.hashers import make_password from django.db.models import Q from rest_framework import serializers -from apps.authentication.exceptions import UserExistException, OrganizationNationalUniqueIDException +from apps.authentication.exceptions import UserExistException, OrganizationNationalUniqueIDException, \ + OrganizationTypeRepeatableException from apps.authentication.models import ( User, City, @@ -231,6 +232,8 @@ class OrganizationSerializer(serializers.ModelSerializer): @ validate national_unique_code to be unique @ validate to organization type field """ + + # check national_unique_id national_unique_id = attrs['national_unique_id'] if not self.instance: @@ -241,6 +244,31 @@ class OrganizationSerializer(serializers.ModelSerializer): if self.Meta.model.objects.filter(national_unique_id=national_unique_id).exists(): raise OrganizationNationalUniqueIDException() + # check organization type field + # if is repeatable of type, organization will not be recreating + org_type = attrs['type'] + if not org_type.is_repeatable: + if org_type.org_type_field == 'PR' and self.Meta.model.objects.filter( + type=org_type, + province=attrs['province'] + ).exists(): + raise OrganizationTypeRepeatableException() + + if org_type.org_type_field == 'CI' and self.Meta.model.objects.filter( + type=org_type, + city=attrs['city'] + ).exists(): + raise OrganizationTypeRepeatableException() + + if org_type.org_type_field == 'CO' and self.Meta.model.objects.filter( + type=org_type, + province=attrs['province'], + city=attrs['city'] + ).exists(): + raise OrganizationTypeRepeatableException() + + return attrs + def to_representation(self, instance): """ Custom output """ representation = super().to_representation(instance) diff --git a/apps/authentication/exceptions.py b/apps/authentication/exceptions.py index e703830..127a190 100644 --- a/apps/authentication/exceptions.py +++ b/apps/authentication/exceptions.py @@ -27,6 +27,14 @@ class OrganizationNationalUniqueIDException(APIException): default_code = 'organization_unique_id_exist' +class OrganizationTypeRepeatableException(APIException): + """ if organization type is repeatable """ + + status_code = status.HTTP_403_FORBIDDEN + default_detail = _('این نوع سازمان قابلیت تکرار ندارد و از قبل وجود دارد') # noqa + default_code = 'organization_type_repeatable' + + class UserExistException(APIException): """ if user exist """ diff --git a/logs/django_requests.log b/logs/django_requests.log index dd2d457..9bbd7b3 100644 --- a/logs/django_requests.log +++ b/logs/django_requests.log @@ -461,3 +461,115 @@ AttributeError: 'NoneType' object has no attribute 'get' [2025-10-29 09:51:33,813] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader [2025-10-29 09:51:47,218] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ [2025-10-29 09:51:47,219] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 86 +[2025-10-29 10:00:27,432] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading. +[2025-10-29 10:00:29,717] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader +[2025-10-29 10:03:41,269] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading. +[2025-10-29 10:03:43,232] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader +[2025-10-29 10:04:47,365] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading. +[2025-10-29 10:04:50,277] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader +[2025-10-29 10:09:32,639] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading. +[2025-10-29 10:09:34,437] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader +[2025-10-29 10:21:27,175] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading. +[2025-10-29 10:21:29,082] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader +[2025-10-29 10:23:50,014] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ +[2025-10-29 10:23:50,040] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 86 +[2025-10-29 10:23:59,952] ERROR django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Internal Server Error: /auth/api/v1/organization/ +Traceback (most recent call last): + File "D:\Software\env\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\django\views\decorators\csrf.py", line 65, in _view_wrapper + return view_func(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\viewsets.py", line 125, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\views.py", line 515, in dispatch + response = self.handle_exception(exc) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\views.py", line 472, in handle_exception + response = exception_handler(exc, context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\views.py", line 512, in dispatch + response = handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\python-3.12.0\Lib\contextlib.py", line 81, in inner + return func(*args, **kwds) + ^^^^^^^^^^^^^^^^^^^ + File "D:\Project\Rasaddam_Backend\apps\authentication\api\v1\api.py", line 265, in create + if serializer.is_valid(): + ^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\serializers.py", line 225, in is_valid + self._validated_data = self.run_validation(self.initial_data) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\serializers.py", line 447, in run_validation + value = self.validate(value) + ^^^^^^^^^^^^^^^^^^^^ + File "D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py", line 251, in validate + if not org_type.is_repeatable(): + ^^^^^^^^^^^^^^^^^^^^^^^^ +TypeError: 'bool' object is not callable +[2025-10-29 10:24:00,000] ERROR django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 500 130816 +[2025-10-29 10:24:19,306] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading. +[2025-10-29 10:24:21,579] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader +[2025-10-29 10:24:29,252] ERROR django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Internal Server Error: /auth/api/v1/organization/ +Traceback (most recent call last): + File "D:\Software\env\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner + response = get_response(request) + ^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\django\views\decorators\csrf.py", line 65, in _view_wrapper + return view_func(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\viewsets.py", line 125, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\views.py", line 515, in dispatch + response = self.handle_exception(exc) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\views.py", line 472, in handle_exception + response = exception_handler(exc, context) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\views.py", line 512, in dispatch + response = handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\python-3.12.0\Lib\contextlib.py", line 81, in inner + return func(*args, **kwds) + ^^^^^^^^^^^^^^^^^^^ + File "D:\Project\Rasaddam_Backend\apps\authentication\api\v1\api.py", line 265, in create + if serializer.is_valid(): + ^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\serializers.py", line 225, in is_valid + self._validated_data = self.run_validation(self.initial_data) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\Software\env\Lib\site-packages\rest_framework\serializers.py", line 448, in run_validation + assert value is not None, '.validate() should return the validated data' +AssertionError: .validate() should return the validated data +[2025-10-29 10:24:29,650] ERROR django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 500 124810 +[2025-10-29 10:24:49,594] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading. +[2025-10-29 10:24:51,318] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader +[2025-10-29 10:24:57,607] INFO django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 201 368 +[2025-10-29 10:25:07,658] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ +[2025-10-29 10:25:07,659] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 86 +[2025-10-29 10:25:14,562] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ +[2025-10-29 10:25:14,562] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 126 +[2025-10-29 10:25:17,922] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ +[2025-10-29 10:25:17,924] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 126 +[2025-10-29 10:26:26,233] INFO django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 201 365 +[2025-10-29 10:26:28,588] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ +[2025-10-29 10:26:28,589] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 86 +[2025-10-29 10:26:33,037] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ +[2025-10-29 10:26:33,038] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 126 +[2025-10-29 10:27:09,481] INFO django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 201 375 +[2025-10-29 10:27:11,414] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ +[2025-10-29 10:27:11,414] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 86 +[2025-10-29 10:27:16,016] WARNING django.request | IP: 127.0.0.1 | Path: /auth/api/v1/organization/ | Forbidden: /auth/api/v1/organization/ +[2025-10-29 10:27:16,017] WARNING django.server | IP: - | Path: - | "POST /auth/api/v1/organization/ HTTP/1.1" 403 126 +[2025-10-29 10:30:41,225] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading. +[2025-10-29 10:30:44,066] INFO django.utils.autoreload | IP: - | Path: - | Watching for file changes with StatReloader +[2025-10-29 10:32:34,721] INFO django.utils.autoreload | IP: - | Path: - | D:\Project\Rasaddam_Backend\apps\authentication\api\v1\serializers\serializer.py changed, reloading.