17 Commits

Author SHA1 Message Date
Shaxobff
5249f7e6f7 my migrations 2026-04-25 12:36:33 +05:00
Shaxobff
e1b771e166 app permission api 20 (api) 2026-04-25 12:32:56 +05:00
Shaxobff
4e242a4358 UPDATE 2026-04-24 17:34:34 +05:00
Shaxobff
c9d60acfc9 UPDATE 2026-04-24 17:07:36 +05:00
Shaxobff
127a2073f8 UPDATE 2026-04-24 16:51:15 +05:00
Shaxobff
3fd0f9959b Merge branch 'main' of https://gitea.felixits.uz/sifatbaho/backend-v1 into shaxob
# Conflicts:
#	core/apps/accounts/serializers/user.py
#	core/apps/accounts/urls.py
#	core/apps/accounts/views/user.py
#	core/apps/evaluation/urls.py
#	core/apps/evaluation/views/request.py
2026-04-24 16:34:02 +05:00
Shaxobff
84cc11fe2a UPDATE 2026-04-24 16:21:19 +05:00
Shaxobff
deebae384c UPDATE 2026-04-24 16:00:17 +05:00
Shaxobff
e27a9b7f11 UPDATE 2026-04-24 11:28:29 +05:00
github-actions[bot]
c89f2b32af 🔄 Update image to 115 [CI SKIP] 2026-04-24 06:23:17 +00:00
Shaxobff
82489cf64c ADD archivedet evaluvation 2026-04-24 11:22:58 +05:00
88dedd85c7 Merge pull request 'Add view for crud user' (#95) from user-crud into main
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 4m15s
Reviewed-on: #95
2026-04-24 06:21:40 +00:00
Shaxobff
af559dadda ADD permission 2026-04-24 11:04:37 +05:00
Shaxobff
d2f8d73cdd /api/v1/admin-user/list/ edit va post 2026-04-23 20:05:16 +05:00
Shaxobff
c4b2a80b2e /api/v1/admin-user/list/ edit va post 2026-04-23 20:03:58 +05:00
Shaxobff
049cd6ff25 /api/v1/admin-user/list/ edit va post 2026-04-23 13:54:31 +05:00
Shaxobff
b8021c7728 add AutoEvaluationRequestView 2026-04-22 14:23:52 +05:00
16 changed files with 350 additions and 24 deletions

View File

@@ -13,7 +13,7 @@ from config.env import env
def home(request):
return HttpResponse("OK: #1a985ffa4b785b63a71b9e0cdd78042c3fcda239")
return HttpResponse("OK: #88dedd85c79ccf732b2adac03616bd14e67a1579")
urlpatterns = [

View File

@@ -0,0 +1,78 @@
# Generated by Django 5.2.7 on 2026-04-24 12:33
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(null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.role'),
),
]

View File

@@ -0,0 +1,60 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from django_core.models import AbstractBaseModel
class PermissionToAction(AbstractBaseModel):
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(AbstractBaseModel):
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(AbstractBaseModel):
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,6 +1,7 @@
from django.contrib.auth import models as auth_models
from django.db import models
from .permission import Role
from ..choices import RoleChoice
from ..managers import UserManager
@@ -17,6 +18,7 @@ class User(auth_models.AbstractUser):
default=RoleChoice.USER,
)
avatar = models.ImageField(upload_to="avatars/", null=True, blank=True)
permission = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True)
USERNAME_FIELD = "phone"
objects = UserManager()

View File

@@ -0,0 +1,26 @@
from rest_framework import serializers
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 = Permission
fields = '__all__'
class RoleSerializer(serializers.ModelSerializer):
class Meta:
model = Role
fields = '__all__'

View File

@@ -42,4 +42,16 @@ class AdminUserSerializer(serializers.ModelSerializer):
request = self.context.get('request')
if obj.avatar:
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,15 +4,22 @@ Accounts app urls
from django.urls import path, include
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 .views.permission import PermissionToActionViewSet, PermissionToTabViewSet, PermissionViewSet, RoleViewSet
router = DefaultRouter()
router.register("auth", RegisterView, basename="auth")
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("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 = [
@@ -26,4 +33,6 @@ urlpatterns = [
),
path("user/list/", UserListApiView.as_view(), name="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

@@ -0,0 +1,42 @@
from django_core.mixins import BaseViewSetMixin
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, PermissionToTab, Permission, Role
from core.apps.accounts.serializers.permission import PermissionToActionSerializer, PermissionToTabSerializer, \
PermissionSerializer, RoleSerializer
@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

View File

@@ -1,18 +1,19 @@
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.permissions import IsAuthenticated
from drf_spectacular.utils import extend_schema
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.response import Response
from rest_framework.views import APIView
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()
@extend_schema(tags=['User'])
class UserListApiView(generics.ListAPIView):
queryset = User.objects.filter(role=RoleChoice.USER)
@@ -32,9 +33,9 @@ class AdminUserListApiView(generics.ListAPIView):
permission_classes = [IsAuthenticated]
filter_backends = [filters.SearchFilter]
search_fields = ['phone', 'first_name', 'last_name']
@extend_schema(tags=["User"],request=AdminUserSerializer)
@extend_schema(tags=["User"], request=AdminUserSerializer)
class AdminUserView(BaseViewSetMixin, ModelViewSet):
queryset = User.objects.filter(role=RoleChoice.USER)
serializer_class = AdminUserSerializer
@@ -45,3 +46,37 @@ class AdminUserView(BaseViewSetMixin, ModelViewSet):
def serializer_context(self):
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

@@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2026-04-24 12:33
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'),
),
]

View File

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

View File

@@ -1,18 +1,20 @@
import re
from django.contrib.auth import get_user_model
from django.contrib.auth import get_user_model
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.models import AutoEvaluationModel, ReferenceitemModel, EvaluationrequestModel
from core.apps.evaluation.serializers.reference import ListReferenceitemSerializer
User = get_user_model()
class BaseAutoevaluationSerializer(serializers.ModelSerializer):
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_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)
value_determined = ListReferenceitemSerializer(read_only=True)
property_rights = ListReferenceitemSerializer(read_only=True)
@@ -72,6 +74,7 @@ class ListAutoevaluationSerializer(BaseAutoevaluationSerializer):
class RetrieveAutoevaluationSerializer(BaseAutoevaluationSerializer):
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)
# object_location_highways_display = serializers.CharField(
# source="get_object_location_highways_display", read_only=True, default=None
# )
@@ -141,7 +144,6 @@ class UpdateAutoevaluationSerializer(serializers.ModelSerializer):
allow_null=True,
)
class Meta:
model = AutoEvaluationModel
fields = [
@@ -222,6 +224,7 @@ class UpdateAutoevaluationSerializer(serializers.ModelSerializer):
return attrs
class CreateAutoevaluationSerializer(serializers.ModelSerializer):
property_rights = serializers.PrimaryKeyRelatedField(
queryset=ReferenceitemModel.objects.all(),
@@ -254,7 +257,6 @@ class CreateAutoevaluationSerializer(serializers.ModelSerializer):
allow_null=True,
)
class Meta:
model = AutoEvaluationModel
fields = [
@@ -356,3 +358,13 @@ class AutoEvaluationAppraisersSerializer(serializers.Serializer):
raise serializers.ValidationError("Invalid appraisers IDs.")
data['users'] = users
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,
CertificateView,
ArchiveQuickEvaluationView,
ArchiveEvaluationrequestView,
ArchiveEvaluationrequestView, GetArchivedEvaluationListAPIView, ArchivedEvaluation,
)
router = DefaultRouter()
@@ -80,4 +80,11 @@ urlpatterns = [
name="evaluation-change-status"),
path("archive/quick-evaluation/", ArchiveQuickEvaluationView.as_view(), name="quick-evaluation-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_core.mixins import BaseViewSetMixin
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, OpenApiParameter
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.generics import GenericAPIView, ListAPIView
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.views import APIView
from rest_framework.viewsets import ModelViewSet
from core.apps.accounts.serializers.user import UserSerializer
from core.apps.evaluation.filters.auto import AutoevaluationFilter
@@ -154,3 +155,21 @@ class AutoEvaluationListAppraisersView(GenericAPIView):
return self.get_paginated_response(serializer.data)
except Exception as e:
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)

View File

View File

@@ -84,7 +84,7 @@ services:
max-file: "5"
web:
image: husanjon/sifatbaho:114
image: husanjon/sifatbaho:115
env_file:
- .env
environment:
@@ -129,7 +129,7 @@ services:
max-file: "5"
celery:
image: husanjon/sifatbaho:114
image: husanjon/sifatbaho:115
env_file:
- .env
environment: