diff --git a/core/apps/accounts/migrations/0004_permissiontoaction_permissiontotab_permission_role_and_more.py b/core/apps/accounts/migrations/0004_permissiontoaction_permissiontotab_permission_role_and_more.py deleted file mode 100644 index e1ccc0f..0000000 --- a/core/apps/accounts/migrations/0004_permissiontoaction_permissiontotab_permission_role_and_more.py +++ /dev/null @@ -1,78 +0,0 @@ -# Generated by Django 5.2.7 on 2026-04-24 12:55 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0003_user_avatar'), - ] - - operations = [ - migrations.CreateModel( - name='PermissionToAction', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('name', models.CharField(max_length=200)), - ('code', models.CharField(max_length=100, unique=True)), - ], - options={ - 'verbose_name': 'Harakatlar uchun ruxsatnoma', - 'verbose_name_plural': 'Harakatlar uchun ruxsatnomalar', - }, - ), - migrations.CreateModel( - name='PermissionToTab', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('name', models.CharField(max_length=200)), - ('code', models.CharField(max_length=100, unique=True)), - ('permission_to_actions', models.ManyToManyField(related_name='permission_to_tabs', to='accounts.permissiontoaction')), - ], - options={ - 'verbose_name': "Bo'lim uchun ruxsatnoma", - 'verbose_name_plural': "Bo'lim uchun ruxsatnomalar", - }, - ), - migrations.CreateModel( - name='Permission', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('name', models.CharField(max_length=200)), - ('code', models.CharField(max_length=100, unique=True)), - ('permission_tab', models.ManyToManyField(related_name='permissions', to='accounts.permissiontotab')), - ], - options={ - 'verbose_name': 'Sahifa uchun ruxsatnoma', - 'verbose_name_plural': 'Sahifa uchun ruxsatnomalar', - }, - ), - migrations.CreateModel( - name='Role', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=200, unique=True)), - ('comment', models.CharField(blank=True, max_length=200, null=True)), - ('permission_to_actions', models.ManyToManyField(blank=True, related_name='roles', to='accounts.permissiontoaction')), - ('permission_to_tabs', models.ManyToManyField(blank=True, related_name='roles', to='accounts.permissiontotab')), - ('permissions', models.ManyToManyField(blank=True, related_name='roles', to='accounts.permission')), - ], - options={ - 'verbose_name': 'Rol', - 'verbose_name_plural': 'Rollar', - }, - ), - migrations.AddField( - model_name='user', - name='permission', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='users', to='accounts.role'), - ), - ] diff --git a/core/apps/accounts/serializers/permission.py b/core/apps/accounts/serializers/permission.py index e06236b..fdf1d37 100644 --- a/core/apps/accounts/serializers/permission.py +++ b/core/apps/accounts/serializers/permission.py @@ -1,8 +1,26 @@ from rest_framework import serializers -from core.apps.accounts.models.permission import PermissionToAction +from core.apps.accounts.models.permission import PermissionToAction, PermissionToTab, Permission, Role + + +class PermissionToActionSerializer(serializers.ModelSerializer): + class Meta: + model = PermissionToAction + fields = "__all__" + +class PermissionToTabSerializer(serializers.ModelSerializer): + class Meta: + model = PermissionToTab + fields = '__all__' class PermissionSerializer(serializers.ModelSerializer): class Meta: - model = PermissionToAction + model = Permission + fields = '__all__' + + +class RoleSerializer(serializers.ModelSerializer): + class Meta: + model = Role + fields = '__all__' \ No newline at end of file diff --git a/core/apps/accounts/urls.py b/core/apps/accounts/urls.py index 2167172..5ff9a73 100644 --- a/core/apps/accounts/urls.py +++ b/core/apps/accounts/urls.py @@ -8,7 +8,7 @@ from .views import RegisterView, ResetPasswordView, MeView, ChangePasswordView, AdminUserView, AdminCreateAPIView, AdminUpdateAPIView from rest_framework.routers import DefaultRouter -# from .views.permission import PermissionToActionViewSetMixin +from .views.permission import PermissionToActionViewSet, PermissionToTabViewSet, PermissionViewSet, RoleViewSet router = DefaultRouter() router.register("auth", RegisterView, basename="auth") @@ -16,7 +16,10 @@ router.register("auth", ResetPasswordView, basename="reset-password") router.register("auth", MeView, basename="me") router.register("auth", ChangePasswordView, basename="change-password") router.register("user", AdminUserView, basename="user-crud") -# router.register("user", PermissionToActionViewSetMixin, basename="permission") +router.register("action", PermissionToActionViewSet, basename="action") +router.register("permission-to-tab", PermissionToTabViewSet, basename="permission-to-tab") +router.register("permission", PermissionViewSet, basename="permission") +router.register("permission-role", RoleViewSet, basename="permission-role") urlpatterns = [ diff --git a/core/apps/accounts/views/permission.py b/core/apps/accounts/views/permission.py index c395857..4d82f49 100644 --- a/core/apps/accounts/views/permission.py +++ b/core/apps/accounts/views/permission.py @@ -1,18 +1,42 @@ from django_core.mixins import BaseViewSetMixin -from rest_framework.permissions import AllowAny +from drf_spectacular.utils import extend_schema +from rest_framework.permissions import AllowAny, IsAdminUser +from rest_framework.viewsets import ModelViewSet -from core.apps.accounts.models.permission import PermissionToAction -from core.apps.accounts.serializers.permission import PermissionSerializer +from core.apps.accounts.models.permission import PermissionToAction, PermissionToTab, Permission, Role +from core.apps.accounts.serializers.permission import PermissionToActionSerializer, PermissionToTabSerializer, \ + PermissionSerializer, RoleSerializer -# class PermissionToActionViewSetMixin(BaseViewSetMixin): -# queryset = PermissionToAction.objects.all() -# permission_classes = [AllowAny] -# serializer_class = PermissionSerializer -# -# action_permission_classes = {} -# action_serializer_class = { -# "list": PermissionSerializer, -# "retrieve": PermissionSerializer, -# "create": PermissionSerializer, -# } +@extend_schema(tags=["permission"]) +class PermissionToActionViewSet(BaseViewSetMixin, ModelViewSet): + queryset = PermissionToAction.objects.all() + serializer_class = PermissionToActionSerializer + + action_serializer_class = { + 'create': PermissionToActionSerializer, + 'update': PermissionToActionSerializer, + } + + action_permission_classes = { + 'create': [AllowAny], + 'destroy': [IsAdminUser], + } + + +@extend_schema(tags=["permission"]) +class PermissionToTabViewSet(BaseViewSetMixin, ModelViewSet): + queryset = PermissionToTab.objects.all() + serializer_class = PermissionToTabSerializer + + + +@extend_schema(tags=["permission"]) +class PermissionViewSet(BaseViewSetMixin, ModelViewSet): + queryset = Permission.objects.all() + serializer_class = PermissionSerializer + + +class RoleViewSet(BaseViewSetMixin, ModelViewSet): + queryset = Role.objects.all() + serializer_class = RoleSerializer diff --git a/core/apps/evaluation/migrations/0035_autoevaluationmodel_is_archived.py b/core/apps/evaluation/migrations/0035_autoevaluationmodel_is_archived.py deleted file mode 100644 index 98f698c..0000000 --- a/core/apps/evaluation/migrations/0035_autoevaluationmodel_is_archived.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2026-04-24 12:55 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('evaluation', '0034_remove_certificatemodel_file_url_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='autoevaluationmodel', - name='is_archived', - field=models.BooleanField(default=False, verbose_name='is archived'), - ), - ] diff --git a/core/apps/evaluation/serializers/certificate/certificate.py b/core/apps/evaluation/serializers/certificate/certificate.py index b9afd95..cabd4c1 100644 --- a/core/apps/evaluation/serializers/certificate/certificate.py +++ b/core/apps/evaluation/serializers/certificate/certificate.py @@ -3,6 +3,7 @@ from core.apps.evaluation.models import CertificateModel class BaseCertificateSerializer(serializers.ModelSerializer): + file = serializers.SerializerMethodField() class Meta: model = CertificateModel @@ -10,4 +11,12 @@ class BaseCertificateSerializer(serializers.ModelSerializer): "id", "title", "file", - ] \ No newline at end of file + ] + + def get_file(self, obj): + if obj.file: + request = self.context.get('request') + if request: + return request.build_absolute_uri(obj.file.url) + return obj.file.url + return None \ No newline at end of file diff --git a/core/apps/evaluation/serializers/quick/QuickEvaluation.py b/core/apps/evaluation/serializers/quick/QuickEvaluation.py index 23019f4..caf942e 100644 --- a/core/apps/evaluation/serializers/quick/QuickEvaluation.py +++ b/core/apps/evaluation/serializers/quick/QuickEvaluation.py @@ -128,6 +128,3 @@ class CreateQuickevaluationSerializer(serializers.ModelSerializer): return super().create(validated_data) -class ArchiveQuickevaluationSerializer(serializers.Serializer): - id = serializers.IntegerField(required=True) - is_archive = serializers.BooleanField(required=True) \ No newline at end of file diff --git a/core/apps/evaluation/urls.py b/core/apps/evaluation/urls.py index 1c93b06..0a0101a 100644 --- a/core/apps/evaluation/urls.py +++ b/core/apps/evaluation/urls.py @@ -30,8 +30,9 @@ from .views import ( TechPassportAPIView, EvaluationStatusChange, CertificateView, - ArchiveQuickEvaluationView, - ArchiveEvaluationrequestView, GetArchivedEvaluationListAPIView, ArchivedEvaluation, + ArchiveEvaluationrequestView, GetArchivedAutoEvaluationListAPIView, ArchivedAutoEvaluation, + GetArchivedQuickevaluationListAPIView, ChangeQuickevaluationAPIView, ArchivedReqEvaluation, + GetArchivedReqEvaluationListAPIView, ) router = DefaultRouter() @@ -78,13 +79,21 @@ urlpatterns = [ ), path("evaluation-request//change-status/", EvaluationStatusChange.as_view(), name="evaluation-change-status"), - path("archive/quick-evaluation/", ArchiveQuickEvaluationView.as_view(), name="quick-evaluation-archive"), + path("archive/quick-evaluation/", GetArchivedQuickevaluationListAPIView.as_view(), name="get-quick-evaluation-archive"), + path("archive/quick-evaluation/", ChangeQuickevaluationAPIView.as_view(), name="change-quick-evaluation-archive"), + path("archive/evaluation-request/", ArchiveEvaluationrequestView.as_view(), name="evaluation-request-archive"), - path("archived-evaluvation/", GetArchivedEvaluationListAPIView.as_view(), + path("archived-evaluvation/", GetArchivedAutoEvaluationListAPIView.as_view(), name="archived-evaluation"), - path("auto-evaluvation-change-status/", ArchivedEvaluation.as_view(), + path("auto-evaluvation-change-status/", ArchivedAutoEvaluation.as_view(), name="archived-evaluation"), + path("req-evaluvation-change-status/", ArchivedReqEvaluation.as_view(), + name="archived-req-evaluation"), + + path("req-evaluvation-change-status/", GetArchivedReqEvaluationListAPIView.as_view(), + name="archived-req-evaluation"), + ] diff --git a/core/apps/evaluation/views/auto.py b/core/apps/evaluation/views/auto.py index 1476ecf..cd7a987 100644 --- a/core/apps/evaluation/views/auto.py +++ b/core/apps/evaluation/views/auto.py @@ -158,14 +158,14 @@ class AutoEvaluationListAppraisersView(GenericAPIView): @extend_schema(tags=["AutoEvaluation"]) -class GetArchivedEvaluationListAPIView(ListAPIView): +class GetArchivedAutoEvaluationListAPIView(ListAPIView): permission_classes = [IsAuthenticated] def get_queryset(self): return AutoEvaluationModel.objects.filter(is_archived=True) @extend_schema(tags=["AutoEvaluation"]) -class ArchivedEvaluation(APIView): +class ArchivedAutoEvaluation(APIView): permission_classes = [IsAuthenticated] def post(self, request, pk): diff --git a/core/apps/evaluation/views/certificate.py b/core/apps/evaluation/views/certificate.py index 5df696a..4eba8f7 100644 --- a/core/apps/evaluation/views/certificate.py +++ b/core/apps/evaluation/views/certificate.py @@ -15,7 +15,7 @@ class CertificateView(BaseViewSetMixin, ModelViewSet): parser_classes = [MultiPartParser, FormParser] - filter_backends = [SearchFilter] + filter_backends = [SearchFilter] search_fields = ["title"] pagination_class = None diff --git a/core/apps/evaluation/views/quick.py b/core/apps/evaluation/views/quick.py index d0970ef..7eb80ee 100644 --- a/core/apps/evaluation/views/quick.py +++ b/core/apps/evaluation/views/quick.py @@ -1,14 +1,15 @@ +from django.shortcuts import get_object_or_404 from django_core.mixins import BaseViewSetMixin from django_filters.rest_framework import DjangoFilterBackend -from drf_spectacular.utils import extend_schema, OpenApiResponse +from drf_spectacular.utils import extend_schema +from rest_framework import status from rest_framework.filters import OrderingFilter, SearchFilter +from rest_framework.generics import ListAPIView from rest_framework.parsers import FormParser, MultiPartParser from rest_framework.permissions import AllowAny, IsAuthenticated -from rest_framework.viewsets import ModelViewSet -from rest_framework.generics import GenericAPIView from rest_framework.response import Response -from rest_framework import status -from django.shortcuts import get_object_or_404 +from rest_framework.views import APIView +from rest_framework.viewsets import ModelViewSet from core.apps.evaluation.filters.quick import QuickevaluationFilter from core.apps.evaluation.models import QuickEvaluationModel @@ -16,7 +17,6 @@ from core.apps.evaluation.serializers.quick import ( CreateQuickevaluationSerializer, ListQuickevaluationSerializer, RetrieveQuickevaluationSerializer, - ArchiveQuickevaluationSerializer, ) @@ -56,75 +56,27 @@ class QuickEvaluationView(BaseViewSetMixin, ModelViewSet): "create": CreateQuickevaluationSerializer, } + @extend_schema(tags=["QuickEvaluation"]) -class ArchiveQuickEvaluationView(GenericAPIView): +class ChangeQuickevaluationAPIView(APIView): + + def post(self, request, pk): + instance = get_object_or_404(QuickEvaluationModel, pk=pk) + + is_archived = request.data.get("is_archived") + if is_archived is None: + return Response( + {"error": "Поле 'is_archived' обязательно"}, + status=status.HTTP_400_BAD_REQUEST + ) + instance.is_archived = is_archived + instance.save() + return Response({"success": True}, status=200) + + +@extend_schema(tags=["QuickEvaluation"]) +class GetArchivedQuickevaluationListAPIView(ListAPIView): permission_classes = [IsAuthenticated] - def get_serializer_class(self): - if self.request.method == "GET": - return ListQuickevaluationSerializer - return ArchiveQuickevaluationSerializer - - @extend_schema( - tags=["QuickEvaluation"], - summary="Get archived quick evaluations list", - description=""" - Returns only archived quick evaluations. - - This endpoint works like quick-evaluation/, - but only records with is_archive=True are returned. - """, - responses={200: ListQuickevaluationSerializer(many=True)}, - ) - def get(self, request, *args, **kwargs): - queryset = QuickEvaluationModel.objects.filter( - is_archive=True - ).order_by("-created_at") - - serializer = self.get_serializer(queryset, many=True) - - return Response(serializer.data, status=status.HTTP_200_OK) - - @extend_schema( - tags=["QuickEvaluation"], - summary="Archive or unarchive quick evaluation", - description=""" - Update archive status for quick evaluation. - - - is_archive=true → archive - - is_archive=false → remove from archive - """, - request=ArchiveQuickevaluationSerializer, - responses={ - 200: OpenApiResponse( - description="Archive status updated successfully" - ), - 400: OpenApiResponse( - description="Validation error" - ), - 404: OpenApiResponse( - description="Quick evaluation not found" - ), - }, - ) - def post(self, request, *args, **kwargs): - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - - validated_data = serializer.validated_data - - obj = get_object_or_404( - QuickEvaluationModel, - id=validated_data["id"] - ) - - obj.is_archive = validated_data["is_archive"] - obj.save(update_fields=["is_archive"]) - - return Response( - { - "success": True, - "message": "Archive status updated successfully" - }, - status=status.HTTP_200_OK - ) \ No newline at end of file + def get_queryset(self): + return QuickEvaluationModel.objects.filter(is_archived=True) diff --git a/core/apps/evaluation/views/request.py b/core/apps/evaluation/views/request.py index 0675d6a..83ec350 100644 --- a/core/apps/evaluation/views/request.py +++ b/core/apps/evaluation/views/request.py @@ -1,16 +1,18 @@ from django.shortcuts import get_object_or_404 - from django_core.mixins import BaseViewSetMixin from django_filters.rest_framework import DjangoFilterBackend +from drf_spectacular.utils import OpenApiResponse from drf_spectacular.utils import extend_schema +from rest_framework import status from rest_framework.filters import OrderingFilter, SearchFilter -from rest_framework.pagination import PageNumberPagination -from rest_framework.permissions import AllowAny, IsAuthenticated -from rest_framework.viewsets import ModelViewSet +from rest_framework.generics import GenericAPIView, ListAPIView +from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework import status +from rest_framework.viewsets import ModelViewSet +from core.apps.accounts.choices import RoleChoice +from core.apps.evaluation.choices.request import RequestStatus from core.apps.evaluation.filters.request import EvaluationrequestFilter from core.apps.evaluation.models import EvaluationrequestModel from core.apps.evaluation.serializers.request import ( @@ -19,9 +21,6 @@ from core.apps.evaluation.serializers.request import ( RetrieveEvaluationrequestSerializer, ArchiveEvaluationrequestSerializer, ) -from core.apps.evaluation.choices.request import RequestStatus -from rest_framework.generics import GenericAPIView -from drf_spectacular.utils import OpenApiResponse # class RequestPagination(PageNumberPagination): @@ -85,7 +84,6 @@ class EvaluationrequestView(BaseViewSetMixin, ModelViewSet): ).order_by("-created_at") - @extend_schema(tags=["EvaluationRequest"]) class AdminEvaluationrequestView(BaseViewSetMixin, ModelViewSet): serializer_class = ListEvaluationrequestSerializer @@ -133,7 +131,8 @@ class AdminEvaluationrequestView(BaseViewSetMixin, ModelViewSet): } def get_queryset(self): - return EvaluationrequestModel.objects.select_related("value_determined", "rate_goal", "property_rights", "form_ownership", "user").order_by("-created_at") + return EvaluationrequestModel.objects.select_related("value_determined", "rate_goal", "property_rights", + "form_ownership", "user").order_by("-created_at") def serializer_context(self): return self.serializer_class(context={"request": self.request}) @@ -149,7 +148,6 @@ class EvaluationStatusChange(APIView): evaluation = get_object_or_404(EvaluationrequestModel, pk=pk) - status_value = request.data.get('status') if not status_value: return Response({'detail': 'Status is required'}, status=status.HTTP_400_BAD_REQUEST) @@ -176,6 +174,7 @@ class EvaluationStatusChange(APIView): 'id': evaluation.pk }) + @extend_schema(tags=["EvaluationRequest"]) class ArchiveEvaluationrequestView(GenericAPIView): permission_classes = [IsAuthenticated] @@ -247,4 +246,25 @@ class ArchiveEvaluationrequestView(GenericAPIView): "message": "Archive status updated successfully" }, status=status.HTTP_200_OK - ) \ No newline at end of file + ) + + +@extend_schema(tags=["EvaluationRequest"]) +class GetArchivedReqEvaluationListAPIView(ListAPIView): + permission_classes = [IsAuthenticated] + + def get_queryset(self): + return EvaluationrequestModel.objects.filter(is_archived=True) + + +@extend_schema(tags=["EvaluationRequest"]) +class ArchivedReqEvaluation(APIView): + permission_classes = [IsAuthenticated] + + def post(self, request, pk): + req_evaluation = get_object_or_404(EvaluationrequestModel, pk=pk) + req_evaluation.is_archived = request.data["is_archived"] + req_evaluation.save() + return Response({"success": True, + "status": req_evaluation.status, + "id": req_evaluation.pk}, status=200)