Merge pull request 'shaxob' (#97) from shaxob into main
Some checks failed
Deploy to Production / build-and-deploy (push) Failing after 49s

Reviewed-on: #97
This commit is contained in:
2026-04-24 11:40:31 +00:00
9 changed files with 177 additions and 21 deletions

View File

@@ -3,6 +3,7 @@ from django.db import models
from ..choices import RoleChoice from ..choices import RoleChoice
from ..managers import UserManager from ..managers import UserManager
from ...evaluation.permissions.permission import Role
class User(auth_models.AbstractUser): class User(auth_models.AbstractUser):
@@ -17,6 +18,7 @@ class User(auth_models.AbstractUser):
default=RoleChoice.USER, default=RoleChoice.USER,
) )
avatar = models.ImageField(upload_to="avatars/", null=True, blank=True) avatar = models.ImageField(upload_to="avatars/", null=True, blank=True)
permission = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True)
USERNAME_FIELD = "phone" USERNAME_FIELD = "phone"
objects = UserManager() objects = UserManager()

View File

@@ -42,4 +42,16 @@ class AdminUserSerializer(serializers.ModelSerializer):
request = self.context.get('request') request = self.context.get('request')
if obj.avatar: if obj.avatar:
return request.build_absolute_uri(obj.avatar.url) return request.build_absolute_uri(obj.avatar.url)
return None return None
class UserCreateSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = [
"phone",
"first_name",
"last_name",
"password",
"role"]

View File

@@ -4,7 +4,8 @@ Accounts app urls
from django.urls import path, include from django.urls import path, include
from rest_framework_simplejwt import views as jwt_views from rest_framework_simplejwt import views as jwt_views
from .views import RegisterView, ResetPasswordView, MeView, ChangePasswordView, UserListApiView, AdminUserListApiView,AdminUserView from .views import RegisterView, ResetPasswordView, MeView, ChangePasswordView, UserListApiView, AdminUserListApiView, \
AdminUserView, AdminCreateAPIView, AdminUpdateAPIView
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
router = DefaultRouter() router = DefaultRouter()
@@ -26,4 +27,6 @@ urlpatterns = [
), ),
path("user/list/", UserListApiView.as_view(), name="user-list"), path("user/list/", UserListApiView.as_view(), name="user-list"),
path("admin-user/list/", AdminUserListApiView.as_view(), name="admin-user-list"), path("admin-user/list/", AdminUserListApiView.as_view(), name="admin-user-list"),
path("admin/create/", AdminCreateAPIView.as_view(), name="user-create"),
path("admin/update/", AdminUpdateAPIView.as_view(), name="user-update"),
] ]

View File

@@ -1,18 +1,19 @@
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.shortcuts import get_object_or_404
from django_core.mixins import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from rest_framework import generics, filters from rest_framework import generics, filters
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from drf_spectacular.utils import extend_schema from rest_framework.views import APIView
from core.apps.accounts.serializers.user import UserSerializer, AdminUserSerializer
from core.apps.accounts.choices.user import RoleChoice
from django_core.mixins import BaseViewSetMixin
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from core.apps.accounts.choices.user import RoleChoice
from core.apps.accounts.serializers.user import UserSerializer, AdminUserSerializer, UserCreateSerializer
User = get_user_model() User = get_user_model()
@extend_schema(tags=['User']) @extend_schema(tags=['User'])
class UserListApiView(generics.ListAPIView): class UserListApiView(generics.ListAPIView):
queryset = User.objects.filter(role=RoleChoice.USER) queryset = User.objects.filter(role=RoleChoice.USER)
@@ -32,9 +33,9 @@ class AdminUserListApiView(generics.ListAPIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
filter_backends = [filters.SearchFilter] filter_backends = [filters.SearchFilter]
search_fields = ['phone', 'first_name', 'last_name'] search_fields = ['phone', 'first_name', 'last_name']
@extend_schema(tags=["User"],request=AdminUserSerializer)
@extend_schema(tags=["User"], request=AdminUserSerializer)
class AdminUserView(BaseViewSetMixin, ModelViewSet): class AdminUserView(BaseViewSetMixin, ModelViewSet):
queryset = User.objects.filter(role=RoleChoice.USER) queryset = User.objects.filter(role=RoleChoice.USER)
serializer_class = AdminUserSerializer serializer_class = AdminUserSerializer
@@ -45,3 +46,37 @@ class AdminUserView(BaseViewSetMixin, ModelViewSet):
def serializer_context(self): def serializer_context(self):
return self.serializer_class(context={"request": self.request}) return self.serializer_class(context={"request": self.request})
@extend_schema(tags=['User'],
responses={200: UserSerializer},
request=UserCreateSerializer)
class AdminCreateAPIView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
if request.user.role not in (RoleChoice.SUPERUSER, RoleChoice.ADMIN):
return Response({'detail': 'Forbidden'}, status=403)
serializer = UserCreateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=201)
@extend_schema(tags=['User'],
responses={200: UserSerializer},
request=UserCreateSerializer)
class AdminUpdateAPIView(APIView):
permission_classes = [IsAuthenticated]
def put(self, request, pk):
if request.user.role not in (RoleChoice.SUPERUSER, RoleChoice.ADMIN):
return Response({'detail': 'Forbidden'}, status=403)
user = get_object_or_404(User, pk=pk)
serializer = UserCreateSerializer(user, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=200)

View File

@@ -267,6 +267,12 @@ class AutoEvaluationModel(AbstractBaseModel):
choices=AutoEvaluationStatus.choices, choices=AutoEvaluationStatus.choices,
default=AutoEvaluationStatus.CREATED, default=AutoEvaluationStatus.CREATED,
) )
is_archived = models.BooleanField(
verbose_name=_("is archived"),
default=False,
)
def __str__(self): def __str__(self):
return f"Auto Evaluation {self.registration_number or self.pk}" return f"Auto Evaluation {self.registration_number or self.pk}"

View File

@@ -0,0 +1,60 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from pydantic import BaseModel
class PermissionToAction(BaseModel):
name = models.CharField(max_length=200)
code = models.CharField(max_length=100, unique=True)
def __str__(self):
return f"{self.name} - {self.code}"
class Meta:
verbose_name = _('Harakatlar uchun ruxsatnoma')
verbose_name_plural = _('Harakatlar uchun ruxsatnomalar')
class PermissionToTab(BaseModel):
name = models.CharField(max_length=200)
code = models.CharField(max_length=100, unique=True)
permission_to_actions = models.ManyToManyField(
PermissionToAction, related_name='permission_to_tabs'
)
def __str__(self):
return f'{self.name} - {self.code}'
class Meta:
verbose_name = _("Bo'lim uchun ruxsatnoma")
verbose_name_plural = _("Bo'lim uchun ruxsatnomalar")
class Permission(BaseModel):
name = models.CharField(max_length=200)
code = models.CharField(max_length=100, unique=True)
permission_tab = models.ManyToManyField(PermissionToTab, related_name='permissions')
def __str__(self):
return f'{self.name} - {self.code}'
class Meta:
verbose_name = _('Sahifa uchun ruxsatnoma')
verbose_name_plural = _('Sahifa uchun ruxsatnomalar')
class Role(models.Model):
name = models.CharField(max_length=200, unique=True)
permissions = models.ManyToManyField(Permission, related_name='roles', blank=True)
permission_to_tabs = models.ManyToManyField(PermissionToTab, related_name='roles', blank=True)
permission_to_actions = models.ManyToManyField(
PermissionToAction, related_name='roles', blank=True
)
comment = models.CharField(max_length=200, null=True, blank=True)
def __str__(self):
return self.name
class Meta:
verbose_name = _('Rol')
verbose_name_plural = _('Rollar')

View File

@@ -1,18 +1,20 @@
import re import re
from django.contrib.auth import get_user_model
from django.contrib.auth import get_user_model
from rest_framework import serializers from rest_framework import serializers
from core.apps.evaluation.models import AutoEvaluationModel,ReferenceitemModel, EvaluationrequestModel
from core.apps.evaluation.serializers.reference import ListReferenceitemSerializer
from core.apps.evaluation.choices.request import RequestStatus from core.apps.evaluation.choices.request import RequestStatus
from core.apps.evaluation.models import AutoEvaluationModel, ReferenceitemModel, EvaluationrequestModel
from core.apps.evaluation.serializers.reference import ListReferenceitemSerializer
User = get_user_model() User = get_user_model()
class BaseAutoevaluationSerializer(serializers.ModelSerializer): class BaseAutoevaluationSerializer(serializers.ModelSerializer):
status_display = serializers.CharField(source="get_status_display", read_only=True) status_display = serializers.CharField(source="get_status_display", read_only=True)
object_type_display = serializers.CharField(source="get_object_type_display", read_only=True, default=None) object_type_display = serializers.CharField(source="get_object_type_display", read_only=True, default=None)
object_owner_type_display = serializers.CharField(source="get_object_owner_type_display", read_only=True, default=None) object_owner_type_display = serializers.CharField(source="get_object_owner_type_display", read_only=True,
default=None)
rate_type = ListReferenceitemSerializer(read_only=True) rate_type = ListReferenceitemSerializer(read_only=True)
value_determined = ListReferenceitemSerializer(read_only=True) value_determined = ListReferenceitemSerializer(read_only=True)
property_rights = ListReferenceitemSerializer(read_only=True) property_rights = ListReferenceitemSerializer(read_only=True)
@@ -72,6 +74,7 @@ class ListAutoevaluationSerializer(BaseAutoevaluationSerializer):
class RetrieveAutoevaluationSerializer(BaseAutoevaluationSerializer): class RetrieveAutoevaluationSerializer(BaseAutoevaluationSerializer):
car_type_display = serializers.CharField(source="get_car_type_display", read_only=True, default=None) car_type_display = serializers.CharField(source="get_car_type_display", read_only=True, default=None)
car_wheel_display = serializers.CharField(source="get_car_wheel_display", read_only=True, default=None) car_wheel_display = serializers.CharField(source="get_car_wheel_display", read_only=True, default=None)
# object_location_highways_display = serializers.CharField( # object_location_highways_display = serializers.CharField(
# source="get_object_location_highways_display", read_only=True, default=None # source="get_object_location_highways_display", read_only=True, default=None
# ) # )
@@ -141,7 +144,6 @@ class UpdateAutoevaluationSerializer(serializers.ModelSerializer):
allow_null=True, allow_null=True,
) )
class Meta: class Meta:
model = AutoEvaluationModel model = AutoEvaluationModel
fields = [ fields = [
@@ -222,6 +224,7 @@ class UpdateAutoevaluationSerializer(serializers.ModelSerializer):
return attrs return attrs
class CreateAutoevaluationSerializer(serializers.ModelSerializer): class CreateAutoevaluationSerializer(serializers.ModelSerializer):
property_rights = serializers.PrimaryKeyRelatedField( property_rights = serializers.PrimaryKeyRelatedField(
queryset=ReferenceitemModel.objects.all(), queryset=ReferenceitemModel.objects.all(),
@@ -254,7 +257,6 @@ class CreateAutoevaluationSerializer(serializers.ModelSerializer):
allow_null=True, allow_null=True,
) )
class Meta: class Meta:
model = AutoEvaluationModel model = AutoEvaluationModel
fields = [ fields = [
@@ -356,3 +358,13 @@ class AutoEvaluationAppraisersSerializer(serializers.Serializer):
raise serializers.ValidationError("Invalid appraisers IDs.") raise serializers.ValidationError("Invalid appraisers IDs.")
data['users'] = users data['users'] = users
return data return data
class AutoEvaluationSerializer(serializers.Serializer):
brand = serializers.CharField()
brand_model = serializers.CharField()
year = serializers.CharField()
color = serializers.CharField()
transmission = serializers.CharField()
condition = serializers.CharField()
fuel_type = serializers.CharField()
mileage = serializers.CharField()

View File

@@ -31,7 +31,7 @@ from .views import (
EvaluationStatusChange, EvaluationStatusChange,
CertificateView, CertificateView,
ArchiveQuickEvaluationView, ArchiveQuickEvaluationView,
ArchiveEvaluationrequestView, ArchiveEvaluationrequestView, GetArchivedEvaluationListAPIView, ArchivedEvaluation,
) )
router = DefaultRouter() router = DefaultRouter()
@@ -80,4 +80,11 @@ urlpatterns = [
name="evaluation-change-status"), name="evaluation-change-status"),
path("archive/quick-evaluation/", ArchiveQuickEvaluationView.as_view(), name="quick-evaluation-archive"), path("archive/quick-evaluation/", ArchiveQuickEvaluationView.as_view(), name="quick-evaluation-archive"),
path("archive/evaluation-request/", ArchiveEvaluationrequestView.as_view(), name="evaluation-request-archive"), path("archive/evaluation-request/", ArchiveEvaluationrequestView.as_view(), name="evaluation-request-archive"),
path("archived-evaluvation/", GetArchivedEvaluationListAPIView.as_view(),
name="archived-evaluation"),
path("auto-evaluvation-change-status/<int:pk>", ArchivedEvaluation.as_view(),
name="archived-evaluation"),
] ]

View File

@@ -1,13 +1,14 @@
from django.db.models import Q from django.db.models import Q
from django_core.mixins import BaseViewSetMixin
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django_core.mixins import BaseViewSetMixin
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import extend_schema, OpenApiParameter from drf_spectacular.utils import extend_schema, OpenApiParameter
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.generics import GenericAPIView, ListAPIView
from rest_framework.permissions import AllowAny, IsAuthenticated 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.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from core.apps.accounts.serializers.user import UserSerializer from core.apps.accounts.serializers.user import UserSerializer
from core.apps.evaluation.filters.auto import AutoevaluationFilter from core.apps.evaluation.filters.auto import AutoevaluationFilter
@@ -154,3 +155,21 @@ class AutoEvaluationListAppraisersView(GenericAPIView):
return self.get_paginated_response(serializer.data) return self.get_paginated_response(serializer.data)
except Exception as e: except Exception as e:
return Response({"error": str(e)}, status=500) return Response({"error": str(e)}, status=500)
@extend_schema(tags=["AutoEvaluation"])
class GetArchivedEvaluationListAPIView(ListAPIView):
permission_classes = [IsAuthenticated]
def get_queryset(self):
return AutoEvaluationModel.objects.filter(is_archived=True)
@extend_schema(tags=["AutoEvaluation"])
class ArchivedEvaluation(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, pk):
auto_evaluation = get_object_or_404(AutoEvaluationModel, pk=pk)
auto_evaluation.is_archived = request.data["is_archived"]
auto_evaluation.save()
return Response({"success": True}, status=200)