diff --git a/config/conf/djangorestframework.py b/config/conf/djangorestframework.py index 1495c72..69af60f 100644 --- a/config/conf/djangorestframework.py +++ b/config/conf/djangorestframework.py @@ -4,4 +4,6 @@ REST_FRAMEWORK = { 'rest_framework.authentication.BasicAuthentication', 'rest_framework_simplejwt.authentication.JWTAuthentication', ], + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', + 'PAGE_SIZE': 10 } \ No newline at end of file diff --git a/config/urls.py b/config/urls.py index 15f5ee6..bbf3c61 100644 --- a/config/urls.py +++ b/config/urls.py @@ -10,11 +10,46 @@ from rest_framework import permissions from drf_yasg.views import get_schema_view from drf_yasg import openapi +description = """ +This API provides backend services for the application, allowing users to authenticate, manage their profiles, and interact with various system resources. + +Authentication: +- The API uses JWT-based authentication. +- To access protected endpoints, include the header: `Authorization: Bearer `. +- Tokens can be obtained from the authentication endpoints (login, refresh). + +Request Format: +- All requests must be sent in JSON format unless otherwise specified. +- File uploads should use multipart/form-data. + +Response Format: +- All responses follow a unified structure containing: + - status_code + - status (success, failure, error, not_found, created, deleted) + - message + - data (optional) +- Error responses include detailed validation messages if applicable. + +Pagination: +- Pagination is supported using `limit` and `offset` query parameters. +- Default limit and maximum allowed limit may vary per endpoint. + +Versioning: +- Current API version: v1. + +Notes: +- Some endpoints require elevated permissions (e.g., admin access). +- All timestamps are returned in ISO 8601 format. +- For secure token storage, avoid exposing refresh tokens on client-side environments. + +Use this documentation to explore available endpoints, inspect request/response formats, and test API calls interactively. +""" + schema_view = get_schema_view( openapi.Info( title="Qurilish Boshqaruv API", default_version='v1', - description="Qurilish boshqaruv api", + description=description, terms_of_service="https://www.google.com/policies/terms/", contact=openapi.Contact(email="xoliqberdiyevbehruz12@gmail.com"), license=openapi.License(name="Behruz's-Organization License"), diff --git a/core/apps/accounts/serializers/user/user.py b/core/apps/accounts/serializers/user/user.py index 6ac0580..715e3a2 100644 --- a/core/apps/accounts/serializers/user/user.py +++ b/core/apps/accounts/serializers/user/user.py @@ -19,4 +19,20 @@ class UserSerializer(serializers.ModelSerializer): 'created_at', 'updated_at', ] - \ No newline at end of file + + +class ListUserSerializer(UserSerializer): + role = serializers.SerializerMethodField(method_name='get_role') + + class Meta: + model = User + fields = UserSerializer.Meta.fields + [ + 'is_active', + 'role' + ] + + def get_role(self, obj): + return { + 'id': obj.role.id, + 'name': obj.role.name, + } if obj.role else {} \ No newline at end of file diff --git a/core/apps/accounts/urls.py b/core/apps/accounts/urls.py index b3526fe..6c66607 100644 --- a/core/apps/accounts/urls.py +++ b/core/apps/accounts/urls.py @@ -9,6 +9,7 @@ from rest_framework.routers import DefaultRouter # ------- user ------ from core.apps.accounts.views.user import UserViewSet from core.apps.accounts.views.user.create import CreateUserApiView +from core.apps.accounts.views.user.list import ListUserApiView # ------- auth ------ from core.apps.accounts.views.auth.login import LoginApiView @@ -17,6 +18,7 @@ urlpatterns = [ path('user/', include( [ path('create/', CreateUserApiView.as_view(), name='user-create-api'), + path('list/', ListUserApiView.as_view(), name='user-list-api'), ] )), # ------ authentication ------ diff --git a/core/apps/accounts/views/auth/login.py b/core/apps/accounts/views/auth/login.py index a11f5a3..159c3d7 100644 --- a/core/apps/accounts/views/auth/login.py +++ b/core/apps/accounts/views/auth/login.py @@ -21,6 +21,32 @@ class LoginApiView(generics.GenericAPIView, ResponseMixin): @swagger_auto_schema( tags=["auth"], + operation_summary="Authenticate a user and returns access/refresh tokens", + operation_description=""" + Authenticate a user using their login credentials and return JWT tokens. + + Request: + - Accepts user login credentials in JSON format. + - The payload is validated using the LoginSerializer. + + Process: + - If the credentials are valid, the corresponding user is retrieved. + - A pair of JWT tokens (access and refresh) is generated for the user. + - User data and tokens are returned in the response. + + Response: + - 200 OK: Returns authenticated user details along with access and refresh tokens. + - 400 Bad Request: Returned when validation fails (e.g., invalid credentials or missing fields). + - 500 Internal Server Error: Returned if an unexpected error occurs during authentication. + + Authentication: + - This endpoint does not require authentication. + - It is used to obtain new JWT tokens for authorized access to protected endpoints. + + Notes: + - The response includes both user profile data and JWT token pair. + - Make sure to store the refresh token securely for token renewal flows. + """, responses={ 200: openapi.Response( description="Success", diff --git a/core/apps/accounts/views/user/create.py b/core/apps/accounts/views/user/create.py index 30d4cca..4b4eff1 100644 --- a/core/apps/accounts/views/user/create.py +++ b/core/apps/accounts/views/user/create.py @@ -23,6 +23,23 @@ class CreateUserApiView(generics.GenericAPIView, ResponseMixin): @swagger_auto_schema( tags=['user'], + operation_summary="Api for create employees", + operation_description=""" + Create a new user account. + + Request Body: + - Requires user details based on the serializer fields. + - All required fields must be provided in MULTIPART/DATA format. + + Behavior: + - Validates the incoming data using the serializer. + - If validation succeeds, a new user is created and returned. + - If validation fails, an appropriate error message is returned. + + Response: + - On success: Returns the newly created user object with a success message. + - On error: Returns validation or processing error details. + """, responses={ 201: openapi.Response( description="Created", @@ -44,7 +61,31 @@ class CreateUserApiView(generics.GenericAPIView, ResponseMixin): } } } - ) + ), + 400: openapi.Response( + description="Failure", + schema=None, + examples={ + "application/json": { + "status_code": 400, + "status": "failure", + "message": "Kiritayotgan malumotingizni tekshirib ko'ring", + "data": "string" + } + } + ), + 500: openapi.Response( + description="Error", + schema=None, + examples={ + "application/json": { + "status_code": 500, + "status": "error", + "message": "Xatolik, Iltimos backend dasturchiga murojaat qiling", + "data": "string" + } + } + ), } ) def post(self, request): diff --git a/core/apps/accounts/views/user/list.py b/core/apps/accounts/views/user/list.py new file mode 100644 index 0000000..dcb9a59 --- /dev/null +++ b/core/apps/accounts/views/user/list.py @@ -0,0 +1,107 @@ +# rest framework +from rest_framework import generics, permissions + +# 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 import ListUserSerializer + +# utils +from core.utils.response.mixin import ResponseMixin + + +class ListUserApiView(generics.GenericAPIView, ResponseMixin): + serializer_class = ListUserSerializer + queryset = User.objects.all() + permission_classes = [permissions.IsAuthenticated] + + @swagger_auto_schema( + tags=['user'], + operation_summary="Api for get list of employees", + operation_description=""" + Retrieve a paginated list of employees. + + Authentication: + - This endpoint requires a valid Bearer access token in the Authorization header. + + Query Parameters: + - limit (integer, optional): Maximum number of results per page. Default: 10. + - offset (integer, optional): Position of the page to start retrieving results from. Default: 0. + + Response: + - Returns a list of employees, including basic employee information and pagination details (count, next, previous). + - Data is returned in JSON format. + """, + responses={ + 200: openapi.Response( + description="Success", + schema=None, + examples={ + "application/json": { + "status_code": 200, + "status": "success", + "message": "Users list", + "data": { + "count": 0, + "next": "string", + "previous": "string", + "results": [ + { + "id": 0, + "first_name": "string", + "last_name": "string", + "username": "string", + "phone_number": "string", + "profile_image": "string", + "created_at": "string", + "updated_at": "string", + "is_active": True, + "role": { + "id": 0, + "name": "string", + }, + } + ] + } + } + } + ), + 500: openapi.Response( + description="Error", + schema=None, + examples={ + "application/json": { + "status_code": 500, + "status": "error", + "message": "Xatolik, Iltimos backend dasturchiga murojaat qiling", + "data": "string" + } + } + ) + }, + manual_parameters=[], + ) + def get(self, request): + try: + queryset = self.queryset.select_related('role') + page = self.paginate_queryset(queryset) + print(page) + if page is not None: + serializer = self.serializer_class(page, many=True) + return self.success_response( + data=self.get_paginated_response(serializer.data).data, + message="Users list" + ) + serializer = self.serializer_class(queryset, many=True) + return self.success_response( + data=serializer.data, + message="Users list" + ) + except Exception as e: + return self.error_response( + data=str(e), + ) \ No newline at end of file diff --git a/core/apps/accounts/views/user/user.py b/core/apps/accounts/views/user/user.py index 87227af..38a2dc0 100644 --- a/core/apps/accounts/views/user/user.py +++ b/core/apps/accounts/views/user/user.py @@ -30,7 +30,27 @@ class UserViewSet(viewsets.GenericViewSet, ResponseMixin): @swagger_auto_schema( tags=['user'], - operation_description="User malumotlarini olish uchun api", + operation_summary="Get currently authenticated user's profile", + operation_description=""" + Get information about the currently authenticated user. + + Authentication: + - This endpoint requires an active Bearer access token. + + Process: + - The system retrieves the user associated with the provided token. + - The user's information is serialized using the configured serializer. + - Returns the authenticated user's profile data. + + Response: + - 200 OK: Successfully returns user details. + - 401 Unauthorized: Authorization header is missing or token is invalid. + - 500 Internal Server Error: An unexpected error occurred. + + Notes: + - This endpoint does not require any request parameters. + - Useful for fetching the current user's profile without needing an ID. + """, responses={ 200: openapi.Response( description="Success", @@ -52,7 +72,19 @@ class UserViewSet(viewsets.GenericViewSet, ResponseMixin): } } } - ) + ), + 500: openapi.Response( + description="Error", + schema=None, + examples={ + "application/json": { + "status_code": 500, + "status": "error", + "message": "Xatolik, Iltimos backend dasturchiga murojaat qiling", + "data": "string", + } + } + ), } ) @action(