accounts: user apis done
This commit is contained in:
46
core/apps/accounts/serializers/user/update.py
Normal file
46
core/apps/accounts/serializers/user/update.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# django
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
# rest framework
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
|
# accounts
|
||||||
|
from core.apps.accounts.models import User, Role
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateUserSerializer(serializers.Serializer):
|
||||||
|
first_name = serializers.CharField(required=False)
|
||||||
|
last_name = serializers.CharField(required=False)
|
||||||
|
role_id = serializers.IntegerField()
|
||||||
|
phone_number = serializers.CharField(required=False)
|
||||||
|
username = serializers.CharField(required=False)
|
||||||
|
password = serializers.CharField(required=False)
|
||||||
|
is_active = serializers.BooleanField(default=True)
|
||||||
|
profile_image = serializers.ImageField(required=False)
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
role = Role.objects.filter(id=data['role_id']).first()
|
||||||
|
if not role:
|
||||||
|
raise serializers.ValidationError({"role": "Role not found"})
|
||||||
|
if data.get('username'):
|
||||||
|
if User.objects.filter(username=data['username']).exists():
|
||||||
|
raise serializers.ValidationError({"username": "User with this username already exist, please try another username"})
|
||||||
|
data['role'] = role
|
||||||
|
return data
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
with transaction.atomic():
|
||||||
|
instance.first_name = validated_data.get('first_name', instance.first_name)
|
||||||
|
instance.last_name = validated_data.get('last_name', instance.last_name)
|
||||||
|
instance.role = validated_data.get('role', instance.role)
|
||||||
|
instance.phone_number = validated_data.get('phone_number', instance.phone_number)
|
||||||
|
instance.username = validated_data.get('username', instance.username)
|
||||||
|
instance.is_active = validated_data.get('is_active', instance.is_active)
|
||||||
|
instance.profile_image = validated_data.get('profile_image', instance.profile_image)
|
||||||
|
|
||||||
|
if validated_data.get('password'):
|
||||||
|
instance.set_password(validated_data.get('password'))
|
||||||
|
|
||||||
|
instance.save()
|
||||||
|
return instance
|
||||||
@@ -10,6 +10,8 @@ from rest_framework.routers import DefaultRouter
|
|||||||
from core.apps.accounts.views.user import UserViewSet
|
from core.apps.accounts.views.user import UserViewSet
|
||||||
from core.apps.accounts.views.user.create import CreateUserApiView
|
from core.apps.accounts.views.user.create import CreateUserApiView
|
||||||
from core.apps.accounts.views.user.list import ListUserApiView
|
from core.apps.accounts.views.user.list import ListUserApiView
|
||||||
|
from core.apps.accounts.views.user.update import UpdateUserApiView
|
||||||
|
from core.apps.accounts.views.user.delete import SoftDeleteUserApiView, HardDeleteUserApiView
|
||||||
# ------- auth ------
|
# ------- auth ------
|
||||||
from core.apps.accounts.views.auth.login import LoginApiView
|
from core.apps.accounts.views.auth.login import LoginApiView
|
||||||
|
|
||||||
@@ -19,6 +21,9 @@ urlpatterns = [
|
|||||||
[
|
[
|
||||||
path('create/', CreateUserApiView.as_view(), name='user-create-api'),
|
path('create/', CreateUserApiView.as_view(), name='user-create-api'),
|
||||||
path('list/', ListUserApiView.as_view(), name='user-list-api'),
|
path('list/', ListUserApiView.as_view(), name='user-list-api'),
|
||||||
|
path('<int:id>/update/', UpdateUserApiView.as_view(), name='user-update-api'),
|
||||||
|
path('<int:id>/soft_delete/', SoftDeleteUserApiView.as_view(), name='user-soft-delete-api'),
|
||||||
|
path('<int:id>/hard_delete/', HardDeleteUserApiView.as_view(), name='user-soft-delete-api'),
|
||||||
]
|
]
|
||||||
)),
|
)),
|
||||||
# ------ authentication ------
|
# ------ authentication ------
|
||||||
|
|||||||
100
core/apps/accounts/views/user/delete.py
Normal file
100
core/apps/accounts/views/user/delete.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# rest framework
|
||||||
|
from rest_framework import views, permissions
|
||||||
|
|
||||||
|
# drf yasg
|
||||||
|
from drf_yasg import openapi
|
||||||
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
|
|
||||||
|
|
||||||
|
# accounts
|
||||||
|
from core.apps.accounts.models import User
|
||||||
|
|
||||||
|
# utils
|
||||||
|
from core.utils.response.mixin import ResponseMixin
|
||||||
|
|
||||||
|
|
||||||
|
class SoftDeleteUserApiView(views.APIView, ResponseMixin):
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
|
@swagger_auto_schema(
|
||||||
|
tags=['user'],
|
||||||
|
operation_summary="Soft delete a user by ID",
|
||||||
|
operation_description="""
|
||||||
|
Mark a user as deleted without permanently removing them from the database.
|
||||||
|
|
||||||
|
Authentication:
|
||||||
|
- Requires a valid Bearer access token.
|
||||||
|
|
||||||
|
Process:
|
||||||
|
- The system retrieves the user by the provided ID.
|
||||||
|
- If the user exists, the `is_deleted` flag is set to True.
|
||||||
|
- The user record remains in the database but is considered inactive/deleted.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
- 200 OK: User successfully soft deleted.
|
||||||
|
- 404 Not Found: No user found with the given ID.
|
||||||
|
- 500 Internal Server Error: Unexpected error occurred during deletion.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- This endpoint only marks the user as deleted and does not remove related data.
|
||||||
|
- Only authenticated users with proper permissions can perform this action.
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
def delete(self, request, id):
|
||||||
|
try:
|
||||||
|
user = User.objects.filter(id=id).first()
|
||||||
|
if not user:
|
||||||
|
return self.not_found_response(message="User not found with this id")
|
||||||
|
user.is_deleted = True
|
||||||
|
user.save()
|
||||||
|
return self.deleted_response(
|
||||||
|
message="User successfully deleted",
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return self.error_response(
|
||||||
|
data=str(e)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class HardDeleteUserApiView(views.APIView, ResponseMixin):
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
|
@swagger_auto_schema(
|
||||||
|
tags=['user'],
|
||||||
|
operation_summary="Permanently delete a user by ID.",
|
||||||
|
operation_description="""
|
||||||
|
Permanently remove a user from the database by their ID.
|
||||||
|
|
||||||
|
Authentication:
|
||||||
|
- Requires a valid Bearer access token.
|
||||||
|
|
||||||
|
Process:
|
||||||
|
- The system retrieves the user by the provided ID.
|
||||||
|
- If the user exists, the user record is permanently deleted from the database.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
- 200 OK: User successfully deleted.
|
||||||
|
- 404 Not Found: No user found with the given ID.
|
||||||
|
- 500 Internal Server Error: Unexpected error occurred during deletion.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- This action permanently removes the user and cannot be undone.
|
||||||
|
- Only authenticated users with proper permissions can perform this action.
|
||||||
|
- All related data handling (foreign keys, constraints) depends on the database setup.
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
def delete(self, request, id):
|
||||||
|
try:
|
||||||
|
user = User.objects.filter(id=id).first()
|
||||||
|
if not user:
|
||||||
|
return self.not_found_response(message="User not found with this id")
|
||||||
|
user.delete()
|
||||||
|
return self.deleted_response(
|
||||||
|
message="User successfully deleted",
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return self.error_response(
|
||||||
|
data=str(e)
|
||||||
|
)
|
||||||
134
core/apps/accounts/views/user/update.py
Normal file
134
core/apps/accounts/views/user/update.py
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
# rest framework
|
||||||
|
from rest_framework import generics, permissions, parsers
|
||||||
|
|
||||||
|
# drf yasg
|
||||||
|
from drf_yasg import openapi
|
||||||
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
|
|
||||||
|
|
||||||
|
# accounts
|
||||||
|
from core.apps.accounts.models import User
|
||||||
|
from core.apps.accounts.serializers.user.update import UpdateUserSerializer
|
||||||
|
from core.apps.accounts.serializers.user.user import UserSerializer
|
||||||
|
|
||||||
|
# utils
|
||||||
|
from core.utils.response.mixin import ResponseMixin
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateUserApiView(generics.GenericAPIView, ResponseMixin):
|
||||||
|
serializer_class = UpdateUserSerializer
|
||||||
|
queryset = User.objects.all()
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
parser_classes = [parsers.MultiPartParser, parsers.FormParser]
|
||||||
|
|
||||||
|
@swagger_auto_schema(
|
||||||
|
tags=['user'],
|
||||||
|
operation_summary="Api for update user with id",
|
||||||
|
operation_description="""
|
||||||
|
Update the information of an existing user using their ID.
|
||||||
|
|
||||||
|
Authentication:
|
||||||
|
- Requires a valid Bearer access token.
|
||||||
|
|
||||||
|
Process:
|
||||||
|
- The system retrieves the user by the provided ID.
|
||||||
|
- If the user exists, the incoming data is validated using the UpdateUserSerializer.
|
||||||
|
- Valid fields are updated and saved.
|
||||||
|
- Returns the updated user data on success.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
- Accepts partial user data (PATCH).
|
||||||
|
- Request format is multipart/form-data
|
||||||
|
- Fields can include first_name, last_name, username, phone_number, profile_image, and others defined in the serializer.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
- 200 OK: Successfully updates and returns the updated user information.
|
||||||
|
- 400 Bad Request: Returned when input validation fails.
|
||||||
|
- 404 Not Found: Returned when there is no user associated with the given ID.
|
||||||
|
- 500 Internal Server Error: Returned when an unexpected error occurs.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Only authenticated users can access this endpoint.
|
||||||
|
- Supports partial updates, meaning not all fields are required.
|
||||||
|
""",
|
||||||
|
responses={
|
||||||
|
200: openapi.Response(
|
||||||
|
schema=None,
|
||||||
|
description="Success",
|
||||||
|
examples={
|
||||||
|
"application/json": {
|
||||||
|
"status_code": 200,
|
||||||
|
"status": "success",
|
||||||
|
"message": "User successfully updated",
|
||||||
|
"data": {
|
||||||
|
"id": 0,
|
||||||
|
"first_name": "sting",
|
||||||
|
"last_name": "sting",
|
||||||
|
"phone_number": "sting",
|
||||||
|
"username": "sting",
|
||||||
|
"profile_image": "sting",
|
||||||
|
"created_at": "sting",
|
||||||
|
"updated_at": "sting",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
404: openapi.Response(
|
||||||
|
schema=None,
|
||||||
|
description="Not Found",
|
||||||
|
examples={
|
||||||
|
"application/json": {
|
||||||
|
"status_code": 404,
|
||||||
|
"status": "not_found",
|
||||||
|
"message": "User not found with given id",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
400: openapi.Response(
|
||||||
|
schema=None,
|
||||||
|
description="Failure",
|
||||||
|
examples={
|
||||||
|
"application/json": {
|
||||||
|
"status_code": 400,
|
||||||
|
"status": "failure",
|
||||||
|
"message": "Kiritayotgan malumotingizni tekshirib ko'ring",
|
||||||
|
"data": "string",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
500: openapi.Response(
|
||||||
|
schema=None,
|
||||||
|
description="Error",
|
||||||
|
examples={
|
||||||
|
"application/json": {
|
||||||
|
"status_code": 500,
|
||||||
|
"status": "error",
|
||||||
|
"message": "Xatolik, Iltimos backend dasturchiga murojaat qiling",
|
||||||
|
"data": "string",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
def patch(self, request, id):
|
||||||
|
try:
|
||||||
|
instance = User.objects.filter(id=id).first()
|
||||||
|
if not instance:
|
||||||
|
return self.not_found_response(data={}, message="User not found with given id")
|
||||||
|
serializer = self.serializer_class(
|
||||||
|
data=request.data, instance=instance, partial=True
|
||||||
|
)
|
||||||
|
if serializer.is_valid():
|
||||||
|
updated_instance = serializer.save()
|
||||||
|
return self.success_response(
|
||||||
|
data=UserSerializer(updated_instance).data,
|
||||||
|
message="User successfully updated"
|
||||||
|
)
|
||||||
|
return self.failure_response(
|
||||||
|
data=serializer.errors,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return self.error_response(
|
||||||
|
data=str(e)
|
||||||
|
)
|
||||||
@@ -46,7 +46,7 @@ class ResponseMixin:
|
|||||||
response_data["message"] = "Kiritayotgan malumotingizni tekshirib ko'ring"
|
response_data["message"] = "Kiritayotgan malumotingizni tekshirib ko'ring"
|
||||||
if data is not None:
|
if data is not None:
|
||||||
response_data["data"] = data
|
response_data["data"] = data
|
||||||
return
|
return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def not_found_response(cls, data=None, message=None):
|
def not_found_response(cls, data=None, message=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user