From 58cc36a9a4711195f654f315d3cdba2a4f78ce0c Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Tue, 2 Sep 2025 17:03:43 +0500 Subject: [PATCH] add: add admin panel api for user --- core/apps/admin_panel/__init__.py | 0 core/apps/admin_panel/apps.py | 6 ++ core/apps/admin_panel/migrations/__init__.py | 0 core/apps/admin_panel/serializers/__init__.py | 0 core/apps/admin_panel/serializers/user.py | 40 ++++++++++ core/apps/admin_panel/urls.py | 15 ++++ core/apps/admin_panel/views/__init__.py | 0 core/apps/admin_panel/views/user.py | 74 +++++++++++++++++++ core/apps/shared/mixins/response.py | 48 ++++++++++++ 9 files changed, 183 insertions(+) create mode 100644 core/apps/admin_panel/__init__.py create mode 100644 core/apps/admin_panel/apps.py create mode 100644 core/apps/admin_panel/migrations/__init__.py create mode 100644 core/apps/admin_panel/serializers/__init__.py create mode 100644 core/apps/admin_panel/serializers/user.py create mode 100644 core/apps/admin_panel/urls.py create mode 100644 core/apps/admin_panel/views/__init__.py create mode 100644 core/apps/admin_panel/views/user.py create mode 100644 core/apps/shared/mixins/response.py diff --git a/core/apps/admin_panel/__init__.py b/core/apps/admin_panel/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/admin_panel/apps.py b/core/apps/admin_panel/apps.py new file mode 100644 index 0000000..95805e5 --- /dev/null +++ b/core/apps/admin_panel/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AdminPanelConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'core.apps.admin_panel' diff --git a/core/apps/admin_panel/migrations/__init__.py b/core/apps/admin_panel/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/admin_panel/serializers/__init__.py b/core/apps/admin_panel/serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/admin_panel/serializers/user.py b/core/apps/admin_panel/serializers/user.py new file mode 100644 index 0000000..af7545b --- /dev/null +++ b/core/apps/admin_panel/serializers/user.py @@ -0,0 +1,40 @@ +from django.db import transaction + +from rest_framework import serializers + +from core.apps.accounts.models import User + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = [ + 'id', 'first_name', 'last_name', 'username', 'password' + ] + extra_kwargs = {'id': {'read_only': True}, 'password': {'write_only': True}} + + def validate_username(self, value): + if User.objects.filter(username=value).exists(): + raise serializers.ValidationError("User with this username already exists") + return value + + def create(self, validated_data): + with transaction.atomic(): + user = User.objects.create( + first_name=validated_data.get('first_name'), + last_name=validated_data.get('last_name'), + username=validated_data.get('username'), + ) + user.set_password(validated_data.get('password')) + user.save() + return user + + def update(self, instance, validated_data): + with transaction.atomic(): + instance.username = validated_data.get('username', instance.username) + instance.first_name = validated_data.get('first_name', instance.first_name) + instance.last_name = validated_data.get('last_name', instance.last_name) + if validated_data.get('password'): + instance.set_password(validated_data.get('password')) + instance.save() + return instance \ No newline at end of file diff --git a/core/apps/admin_panel/urls.py b/core/apps/admin_panel/urls.py new file mode 100644 index 0000000..a9366fd --- /dev/null +++ b/core/apps/admin_panel/urls.py @@ -0,0 +1,15 @@ +from django.urls import path, include + +from core.apps.admin_panel.views import user as user_views + +urlpatterns = [ + path('user/', include( + [ + path('create/', user_views.UserCreateApiView.as_view()), + path('list/', user_views.UserListApiView.as_view()), + path('/update/', user_views.UserUpdateApiView.as_view()), + path('/delete/', user_views.UserDeleteApiView.as_view()), + path('/', user_views.UserDetailApiView.as_view()), + ] + )) +] \ No newline at end of file diff --git a/core/apps/admin_panel/views/__init__.py b/core/apps/admin_panel/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/admin_panel/views/user.py b/core/apps/admin_panel/views/user.py new file mode 100644 index 0000000..b849d38 --- /dev/null +++ b/core/apps/admin_panel/views/user.py @@ -0,0 +1,74 @@ +from django.shortcuts import get_object_or_404 + +from rest_framework import generics, permissions, status +from rest_framework.response import Response + +from core.apps.admin_panel.serializers.user import UserSerializer +from core.apps.accounts.models import User +from core.apps.shared.mixins.response import ResponseMixin + + +class UserCreateApiView(generics.GenericAPIView, ResponseMixin): + serializer_class = UserSerializer + queryset = User.objects.all() + permission_classes = [permissions.IsAdminUser] + + def post(self, request): + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(raise_exception=True): + serializer.save() + return self.success_response( + message='User qoshildi', status_code=status.HTTP_201_CREATED + ) + return self.error_response(data=serializer.errors, message='User qoshishda xatolik') + + +class UserListApiView(generics.GenericAPIView, ResponseMixin): + serializer_class = UserSerializer + queryset = User.objects.exclude(is_superuser=True) + permission_classes = [permissions.IsAdminUser] + + def get(self, request): + users = self.get_queryset() + page = self.paginate_queryset(users) + if page is not None: + serializer = self.serializer_class(page, many=True) + return self.get_paginated_response(serializer.data) + serializer = self.serializer_class(users, many=True) + return self.success_response(data=serializer.data, message='userlar royxati') + + +class UserUpdateApiView(generics.GenericAPIView, ResponseMixin): + serializer_class = UserSerializer + queryset = User.objects.all() + permission_classes = [permissions.IsAdminUser] + + def patch(self, request, id): + user = get_object_or_404(User, id=id) + serializer = self.serializer_class(instance=user, data=serializer.data) + if serializer.is_valid(raise_exception=True): + serializer.save() + return self.success_response(message='user tahrirlandi') + return self.failure_response(data=serializer.errors, message='user tahrirlashda xatolik') + + +class UserDeleteApiView(generics.GenericAPIView, ResponseMixin): + serializer_class = None + queryset = User.objects.all() + permission_classes = [permissions.IsAdminUser] + + def delete(self, request, id): + user = get_object_or_404(User, id=id) + user.delete() + return self.success_response(message='user ochirildi', status_code=status.HTTP_204_NO_CONTENT) + + +class UserDetailApiView(generics.GenericAPIView, ResponseMixin): + serializer_class = UserSerializer + queryset = User.objects.all() + permissions = [permissions.IsAdminUser] + + def get(self, request, id): + user = get_object_or_404(User, id=id) + serializer = self.serializer_class(user) + return self.success_response(data=serializer.data, message='user malumotlari') diff --git a/core/apps/shared/mixins/response.py b/core/apps/shared/mixins/response.py new file mode 100644 index 0000000..4fe4e3c --- /dev/null +++ b/core/apps/shared/mixins/response.py @@ -0,0 +1,48 @@ +from rest_framework import status +from rest_framework.response import Response + + +class ResponseMixin: + SUCCESS = 'success' + FAILURE = 'failure' + ERROR = 'error' + + @classmethod + def success_response(cls, data=None, message=None, status_code=status.HTTP_200_OK): + """ + Returns Success response + """ + response_data = {'status_code': status_code, 'status': cls.SUCCESS} + if message is not None: + response_data['message'] = message + if data is not None: + response_data['data'] = data + return Response(response_data, status=status_code) + + @classmethod + def failure_response( + cls, data=None, message=None, status_code=status.HTTP_400_BAD_REQUEST + ): + """ + Returns Failure Response + """ + response_data = {"status_code": status_code, "status": cls.FAILURE} + if message is not None: + response_data["message"] = message + if data is not None: + response_data["data"] = data + return Response(response_data, status=status_code) + + @classmethod + def error_response( + cls, data=None, message=None, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR + ): + """ + Returns Error Response + """ + response_data = {"status_code": status_code, "status": cls.ERROR} + if message is not None: + response_data["message"] = message + if data is not None: + response_data["data"] = data + return Response(response_data, status=status_code) \ No newline at end of file