From ebd8f876c7419b8ca85beeef896e86c85f3f1109 Mon Sep 17 00:00:00 2001 From: sina_sajjadi Date: Mon, 14 Sep 2026 18:24:49 +0330 Subject: [PATCH] feat: add core backend application structure, enhanced auth middleware, and API components --- apps/__init__.py | 1 + apps/account/admin/notification.py | 29 +- apps/account/models/user.py | 9 +- apps/api/tests.py | 79 +- apps/api/views/api_views.py | 31 +- config/enhanced_auth_middleware.py | 10 +- config/settings/base.py | 1 - dynamic_preferences/admin.py | 1 - requirements.txt | 1 + schema.yml | 3031 ++++++++++++++++++++++++++++ 10 files changed, 3160 insertions(+), 33 deletions(-) create mode 100644 apps/__init__.py create mode 100644 schema.yml diff --git a/apps/__init__.py b/apps/__init__.py new file mode 100644 index 0000000..40c51f1 --- /dev/null +++ b/apps/__init__.py @@ -0,0 +1 @@ +# apps package diff --git a/apps/account/admin/notification.py b/apps/account/admin/notification.py index f62ff66..31c8ea5 100644 --- a/apps/account/admin/notification.py +++ b/apps/account/admin/notification.py @@ -1,14 +1,15 @@ -from django.contrib import admin -from django.utils.translation import gettext_lazy as _ -from ajaxdatatable.admin import AjaxDatatable - -from apps.account.models import User, Notification - -@admin.register(Notification) -class NotificationAdmin(AjaxDatatable): - list_display = ('title', 'user', 'is_read', 'created_at') - list_filter = ('is_read', 'created_at') - search_fields = ('title', 'message', 'user__fullname') - list_editable = ('is_read',) - ordering = ('-created_at',) - autocomplete_fields = ['user',] \ No newline at end of file +from django.contrib import admin +from django.utils.translation import gettext_lazy as _ +from unfold.admin import ModelAdmin +from utils.admin import project_admin_site + +from apps.account.models import User, Notification + +@admin.register(Notification, site=project_admin_site) +class NotificationAdmin(ModelAdmin): + list_display = ('title', 'user', 'is_read', 'created_at') + list_filter = ('is_read', 'created_at') + search_fields = ('title', 'message', 'user__fullname') + list_editable = ('is_read',) + ordering = ('-created_at',) + autocomplete_fields = ['user',] \ No newline at end of file diff --git a/apps/account/models/user.py b/apps/account/models/user.py index e9431cc..b8855c1 100644 --- a/apps/account/models/user.py +++ b/apps/account/models/user.py @@ -20,9 +20,16 @@ class User(AbstractUser): web = 'web', _('Web') class UserType(models.TextChoices): - CLIENT = 'client', _('Client') + CLIENT = 'client', _('Client / User') + STUDENT = 'student', _('Student / Member') + PROFESSOR = 'professor', _('Professor / Scholar') + CONSULTANT = 'consultant', _('Consultant') ADMIN = 'admin', _('Admin') SUPER_ADMIN = 'super_admin', _('Super Admin') + REGIONAL_ADMIN = 'regional_admin', _('Regional Admin') + INSTITUTION_ADMIN = 'institution_admin', _('Institution Admin') + EDITOR = 'editor', _('Editor') + VIEWER = 'viewer', _('Viewer') class GenderChoices(models.TextChoices): MALE = 'male', _('Male') diff --git a/apps/api/tests.py b/apps/api/tests.py index 7ce503c..b15eae2 100644 --- a/apps/api/tests.py +++ b/apps/api/tests.py @@ -1,3 +1,80 @@ from django.test import TestCase +from django.urls import reverse +from rest_framework.test import APIClient +from rest_framework import status +from django.contrib.auth import get_user_model -# Create your tests here. +User = get_user_model() + + +class Phase0InfrastructureTests(TestCase): + """ + Automated verification tests for Phase 0 infrastructure: + - OpenAPI 3.0 schema endpoints via drf-spectacular + - Swagger UI & ReDoc interfaces + - JWT token issue, refresh, and verification endpoints + - Core API health checks + """ + def setUp(self): + self.client = APIClient() + self.user = User.objects.create_user( + email='tester@shiadeepconnect.org', + username='tester@shiadeepconnect.org', + password='SecurePassword123!', + fullname='Tester User' + ) + + def test_health_check_endpoint(self): + response = self.client.get('/api/v1/health/') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data.get('status'), 'healthy') + self.assertEqual(response.data.get('version'), '1.0.0') + + def test_openapi_schema_endpoint(self): + response = self.client.get('/api/schema/') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('openapi', response.content.decode('utf-8')) + + def test_swagger_ui_endpoint(self): + response = self.client.get('/api/schema/swagger-ui/') + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_redoc_endpoint(self): + response = self.client.get('/api/schema/redoc/') + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_swagger_legacy_redirect(self): + response = self.client.get('/swagger/') + self.assertIn(response.status_code, [status.HTTP_302_FOUND, status.HTTP_301_MOVED_PERMANENTLY]) + self.assertEqual(response.url, '/api/schema/swagger-ui/') + + def test_jwt_token_obtain_pair(self): + # Obtain JWT tokens + payload = { + 'email': 'tester@shiadeepconnect.org', + 'password': 'SecurePassword123!' + } + response = self.client.post('/api/v1/auth/token/', payload, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('access', response.data) + self.assertIn('refresh', response.data) + + access_token = response.data['access'] + refresh_token = response.data['refresh'] + + # Verify token + verify_response = self.client.post( + '/api/v1/auth/token/verify/', + {'token': access_token}, + format='json' + ) + self.assertEqual(verify_response.status_code, status.HTTP_200_OK) + + # Refresh token + refresh_response = self.client.post( + '/api/v1/auth/token/refresh/', + {'refresh': refresh_token}, + format='json' + ) + self.assertEqual(refresh_response.status_code, status.HTTP_200_OK) + self.assertIn('access', refresh_response.data) diff --git a/apps/api/views/api_views.py b/apps/api/views/api_views.py index ce45b4d..06c5a28 100644 --- a/apps/api/views/api_views.py +++ b/apps/api/views/api_views.py @@ -7,6 +7,9 @@ from django.utils import timezone from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi +from drf_spectacular.utils import extend_schema, OpenApiResponse, inline_serializer +from rest_framework import serializers + from apps.api.models import AppVersion, SupportMessage from apps.api.serializers import AppVersionSerializer, SupportMessageCreateSerializer @@ -17,17 +20,16 @@ class HealthCheckView(APIView): """ permission_classes = [AllowAny] - @swagger_auto_schema( - operation_description="Check API server health status", + @extend_schema( + summary="Check API server health status", + description="Returns system status, current timestamp, and API version", responses={ - 200: openapi.Response( - description="Server is healthy", - examples={ - "application/json": { - "status": "healthy", - "timestamp": "2026-09-13T12:00:00Z", - "version": "1.0.0" - } + 200: inline_serializer( + name="HealthCheckResponse", + fields={ + "status": serializers.CharField(default="healthy"), + "timestamp": serializers.DateTimeField(), + "version": serializers.CharField(default="1.0.0"), } ) } @@ -46,11 +48,12 @@ class AppVersionView(APIView): """ permission_classes = [AllowAny] - @swagger_auto_schema( - operation_description="Get the latest active mobile application version", + @extend_schema( + summary="Get active application version", + description="Returns latest active mobile/web application version details", responses={ - 200: AppVersionSerializer(), - 404: openapi.Response("No active version found") + 200: AppVersionSerializer, + 404: OpenApiResponse(description="No active version found") } ) def get(self, request): diff --git a/config/enhanced_auth_middleware.py b/config/enhanced_auth_middleware.py index bd82db4..bf2d352 100644 --- a/config/enhanced_auth_middleware.py +++ b/config/enhanced_auth_middleware.py @@ -13,8 +13,16 @@ def enhanced_auth_middleware(get_response): Handles custom documentation system authentication """ def middleware(request): + # Exclude drf-spectacular OpenAPI endpoints so Swagger UI and ReDoc can be accessed + if request.path.startswith("/api/schema/"): + return get_response(request) + + # Legacy swagger redirect allow + if request.path == "/swagger/": + return get_response(request) + # Define protected paths that require staff access - protected_paths = ["/swagger", "/redoc", "/docs"] + protected_paths = ["/docs"] is_protected_path = any(path in request.path for path in protected_paths) if is_protected_path: diff --git a/config/settings/base.py b/config/settings/base.py index b814548..709c67b 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -9,7 +9,6 @@ from django.urls import reverse_lazy import environ from django.utils.translation import gettext_lazy as _ import sentry_sdk -from utils.admin import admin_url_generator # Build paths inside the project: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent.parent diff --git a/dynamic_preferences/admin.py b/dynamic_preferences/admin.py index 369a0e8..6f30740 100644 --- a/dynamic_preferences/admin.py +++ b/dynamic_preferences/admin.py @@ -1,4 +1,3 @@ -from ajaxdatatable.admin import AjaxDatatable from django.contrib import admin from django import forms diff --git a/requirements.txt b/requirements.txt index 56f7d7d..4bb96cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -44,3 +44,4 @@ cachetools>=5.3.0 Unidecode>=1.3.0 persisting-theory>=1.0 django-dynamic-preferences>=1.17.0 +geoip2>=4.8.0 diff --git a/schema.yml b/schema.yml new file mode 100644 index 0000000..7b68a6f --- /dev/null +++ b/schema.yml @@ -0,0 +1,3031 @@ +openapi: 3.0.3 +info: + title: API سامانه تعاملات بین‌الملل + version: 2.0.0 + description: مستندات نقاط پایانی سامانه تعاملات بین‌الملل آستان قدس رضوی (فاز دوم) +paths: + /api/v1/account/admin/directory-users/: + get: + operationId: v1_account_admin_directory_users_list + description: |- + Separate, dedicated endpoint for accounts/users list page. + Filters users who have an email, are not deleted (deleted_at is null). + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedAdminUserList' + description: '' + post: + operationId: v1_account_admin_directory_users_create + description: |- + Separate, dedicated endpoint for accounts/users list page. + Filters users who have an email, are not deleted (deleted_at is null). + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUserRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AdminUserRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AdminUserRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + /api/v1/account/admin/directory-users/{id}/: + get: + operationId: v1_account_admin_directory_users_retrieve + description: |- + Separate, dedicated endpoint for accounts/users list page. + Filters users who have an email, are not deleted (deleted_at is null). + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this User. + required: true + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + put: + operationId: v1_account_admin_directory_users_update + description: |- + Separate, dedicated endpoint for accounts/users list page. + Filters users who have an email, are not deleted (deleted_at is null). + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this User. + required: true + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUserRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AdminUserRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AdminUserRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + patch: + operationId: v1_account_admin_directory_users_partial_update + description: |- + Separate, dedicated endpoint for accounts/users list page. + Filters users who have an email, are not deleted (deleted_at is null). + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this User. + required: true + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedAdminUserRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedAdminUserRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedAdminUserRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + delete: + operationId: v1_account_admin_directory_users_destroy + description: |- + Separate, dedicated endpoint for accounts/users list page. + Filters users who have an email, are not deleted (deleted_at is null). + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this User. + required: true + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/account/admin/directory-users/export_excel/: + get: + operationId: v1_account_admin_directory_users_export_excel_retrieve + description: |- + Export users to an Excel (.xlsx) file. + Accepts user_ids in POST body for selective bulk export, + or uses current queryset filters if no specific IDs are provided. + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + post: + operationId: v1_account_admin_directory_users_export_excel_create + description: |- + Export users to an Excel (.xlsx) file. + Accepts user_ids in POST body for selective bulk export, + or uses current queryset filters if no specific IDs are provided. + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUserRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AdminUserRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AdminUserRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + /api/v1/account/admin/login/: + post: + operationId: v1_account_admin_login_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserLoginRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserLoginRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserLoginRequest' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserLogin' + description: '' + /api/v1/account/admin/notification-templates/: + get: + operationId: v1_account_admin_notification_templates_list + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedNotificationTemplateList' + description: '' + post: + operationId: v1_account_admin_notification_templates_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationTemplateRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/NotificationTemplateRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/NotificationTemplateRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationTemplate' + description: '' + /api/v1/account/admin/notification-templates/{id}/: + get: + operationId: v1_account_admin_notification_templates_retrieve + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Notification Template. + required: true + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationTemplate' + description: '' + put: + operationId: v1_account_admin_notification_templates_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Notification Template. + required: true + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationTemplateRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/NotificationTemplateRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/NotificationTemplateRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationTemplate' + description: '' + patch: + operationId: v1_account_admin_notification_templates_partial_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Notification Template. + required: true + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedNotificationTemplateRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedNotificationTemplateRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedNotificationTemplateRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/NotificationTemplate' + description: '' + delete: + operationId: v1_account_admin_notification_templates_destroy + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Notification Template. + required: true + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/account/admin/notifications/: + get: + operationId: v1_account_admin_notifications_list + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedAdminNotificationList' + description: '' + post: + operationId: v1_account_admin_notifications_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminNotificationRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AdminNotificationRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AdminNotificationRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminNotification' + description: '' + /api/v1/account/admin/notifications/{id}/: + get: + operationId: v1_account_admin_notifications_retrieve + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Notification. + required: true + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminNotification' + description: '' + put: + operationId: v1_account_admin_notifications_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Notification. + required: true + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminNotificationRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AdminNotificationRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AdminNotificationRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminNotification' + description: '' + patch: + operationId: v1_account_admin_notifications_partial_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Notification. + required: true + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedAdminNotificationRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedAdminNotificationRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedAdminNotificationRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminNotification' + description: '' + delete: + operationId: v1_account_admin_notifications_destroy + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Notification. + required: true + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/account/admin/users/: + get: + operationId: v1_account_admin_users_list + description: |- + Admin-only endpoint for full CRUD operations on Users. + Includes searching, filtering, and pagination. + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedAdminUserList' + description: '' + post: + operationId: v1_account_admin_users_create + description: |- + Admin-only endpoint for full CRUD operations on Users. + Includes searching, filtering, and pagination. + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUserRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AdminUserRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AdminUserRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + /api/v1/account/admin/users/{id}/: + get: + operationId: v1_account_admin_users_retrieve + description: |- + Admin-only endpoint for full CRUD operations on Users. + Includes searching, filtering, and pagination. + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this User. + required: true + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + put: + operationId: v1_account_admin_users_update + description: |- + Admin-only endpoint for full CRUD operations on Users. + Includes searching, filtering, and pagination. + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this User. + required: true + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUserRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AdminUserRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AdminUserRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + patch: + operationId: v1_account_admin_users_partial_update + description: |- + Admin-only endpoint for full CRUD operations on Users. + Includes searching, filtering, and pagination. + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this User. + required: true + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedAdminUserRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedAdminUserRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedAdminUserRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + delete: + operationId: v1_account_admin_users_destroy + description: |- + Admin-only endpoint for full CRUD operations on Users. + Includes searching, filtering, and pagination. + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this User. + required: true + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/account/admin/users/export_excel/: + get: + operationId: v1_account_admin_users_export_excel_retrieve + description: |- + Export users to an Excel (.xlsx) file. + Accepts user_ids in POST body for selective bulk export, + or uses current queryset filters if no specific IDs are provided. + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + post: + operationId: v1_account_admin_users_export_excel_create + description: |- + Export users to an Excel (.xlsx) file. + Accepts user_ids in POST body for selective bulk export, + or uses current queryset filters if no specific IDs are provided. + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUserRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AdminUserRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AdminUserRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminUser' + description: '' + /api/v1/account/exchange-token/: + post: + operationId: v1_account_exchange_token_create + description: تبدیل temporary token به اطلاعات کاربر برای ورود از اپ موبایل + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ExchangeTokenRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/ExchangeTokenRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/ExchangeTokenRequest' + required: true + security: + - jwtAuth: [] + - tokenAuth: [] + - cookieAuth: [] + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ExchangeToken' + description: '' + /api/v1/account/guest/: + post: + operationId: v1_account_guest_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserGuestRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserGuestRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserGuestRequest' + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserGuest' + description: '' + /api/v1/account/location-update/: + post: + operationId: v1_account_location_update_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LocationHistoryRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/LocationHistoryRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/LocationHistoryRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/LocationHistory' + description: '' + /api/v1/account/login/: + post: + operationId: v1_account_login_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserLoginRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserLoginRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserLoginRequest' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserLogin' + description: '' + /api/v1/account/notif/: + get: + operationId: v1_account_notif_list + parameters: + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedNotificationList' + description: '' + /api/v1/account/notif/read/: + post: + operationId: v1_account_notif_read_create + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + description: No response body + /api/v1/account/notif/send/: + post: + operationId: v1_account_notif_send_create + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + description: No response body + /api/v1/account/profile/: + get: + operationId: v1_account_profile_retrieve + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserProfile' + description: '' + /api/v1/account/profile/delete/: + delete: + operationId: v1_account_profile_delete_destroy + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/account/profile/update/: + put: + operationId: v1_account_profile_update_update + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserProfileRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserProfileRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserProfileRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserProfile' + description: '' + patch: + operationId: v1_account_profile_update_partial_update + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedUserProfileRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedUserProfileRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedUserProfileRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserProfile' + description: '' + /api/v1/account/recover/: + post: + operationId: v1_account_recover_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserRecoverPasswordRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserRecoverPasswordRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserRecoverPasswordRequest' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserRecoverPassword' + description: '' + /api/v1/account/region-info/: + get: + operationId: v1_account_region_info_retrieve + description: Returns basic client region, browser, and network info + tags: + - v1 + security: + - jwtAuth: [] + - tokenAuth: [] + - cookieAuth: [] + - jwtAuth: [] + - {} + responses: + '200': + description: No response body + /api/v1/account/register/: + post: + operationId: v1_account_register_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserRegisterRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserRegisterRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserRegisterRequest' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserRegister' + description: '' + /api/v1/account/reset/: + post: + operationId: v1_account_reset_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserResetPasswordRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserResetPasswordRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserResetPasswordRequest' + required: true + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '201': + description: No response body + /api/v1/account/update-fcm/: + post: + operationId: v1_account_update_fcm_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserFCMRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserFCMRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserFCMRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserFCM' + description: '' + /api/v1/account/verify/: + post: + operationId: v1_account_verify_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserVerifyRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserVerifyRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserVerifyRequest' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserVerify' + description: '' + /api/v1/account/web/register/: + post: + operationId: v1_account_web_register_create + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WebUserRegisterRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/WebUserRegisterRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/WebUserRegisterRequest' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/WebUserRegister' + description: '' + /api/v1/auth/token/: + post: + operationId: v1_auth_token_create + description: |- + Takes a set of user credentials and returns an access and refresh JSON web + token pair to prove the authentication of those credentials. + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenObtainPairRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenObtainPairRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenObtainPairRequest' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenObtainPair' + description: '' + /api/v1/auth/token/refresh/: + post: + operationId: v1_auth_token_refresh_create + description: |- + Takes a refresh type JSON web token and returns an access type JSON web + token if the refresh token is valid. + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenRefreshRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenRefreshRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenRefreshRequest' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenRefresh' + description: '' + /api/v1/auth/token/verify/: + post: + operationId: v1_auth_token_verify_create + description: |- + Takes a token and indicates if it is valid. This view provides no + information about a token's fitness for a particular use. + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenVerifyRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenVerifyRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenVerifyRequest' + required: true + security: + - jwtAuth: [] + responses: + '200': + description: No response body + /api/v1/contact-us/: + post: + operationId: v1_contact_us_create + description: Submit a user contact or support inquiry + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SupportMessageCreateRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SupportMessageCreateRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/SupportMessageCreateRequest' + required: true + security: + - jwtAuth: [] + - tokenAuth: [] + - cookieAuth: [] + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/SupportMessageCreate' + description: '' + /api/v1/health/: + get: + operationId: v1_health_retrieve + description: Returns system status, current timestamp, and API version + summary: Check API server health status + tags: + - v1 + security: + - jwtAuth: [] + - tokenAuth: [] + - cookieAuth: [] + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/HealthCheckResponse' + description: '' + /api/v1/settings/about-us/: + get: + operationId: v1_settings_about_us_retrieve + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AboutUs' + description: '' + put: + operationId: v1_settings_about_us_update + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AboutUsRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AboutUsRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AboutUsRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AboutUs' + description: '' + /api/v1/settings/about-us-dobodi/: + get: + operationId: v1_settings_about_us_dobodi_retrieve + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AboutUsDobodi' + description: '' + put: + operationId: v1_settings_about_us_dobodi_update + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AboutUsDobodiRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/AboutUsDobodiRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/AboutUsDobodiRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AboutUsDobodi' + description: '' + /api/v1/settings/card/: + get: + operationId: v1_settings_card_retrieve + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Card' + description: '' + put: + operationId: v1_settings_card_update + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CardRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/CardRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/CardRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Card' + description: '' + /api/v1/settings/faq-course/: + get: + operationId: v1_settings_faq_course_retrieve + tags: + - v1 + security: + - jwtAuth: [] + - tokenAuth: [] + - cookieAuth: [] + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FAQItem' + description: '' + /api/v1/settings/faq-general/: + get: + operationId: v1_settings_faq_general_retrieve + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FAQItem' + description: '' + put: + operationId: v1_settings_faq_general_update + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FAQItemRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/FAQItemRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/FAQItemRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/FAQItem' + description: '' + /api/v1/settings/support/: + get: + operationId: v1_settings_support_retrieve + tags: + - v1 + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Support' + description: '' + put: + operationId: v1_settings_support_update + tags: + - v1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SupportRequest' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SupportRequest' + multipart/form-data: + schema: + $ref: '#/components/schemas/SupportRequest' + security: + - tokenAuth: [] + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Support' + description: '' + /api/v1/version/: + get: + operationId: v1_version_retrieve + description: Returns latest active mobile/web application version details + summary: Get active application version + tags: + - v1 + security: + - jwtAuth: [] + - tokenAuth: [] + - cookieAuth: [] + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AppVersion' + description: '' + '404': + description: No active version found +components: + schemas: + AboutUs: + type: object + properties: + content: + type: string + default: '' + AboutUsDobodi: + type: object + properties: + arabic_text: + type: string + default: '' + translated_text: + type: string + default: '' + title: + type: string + default: '' + content: + type: string + default: '' + AboutUsDobodiRequest: + type: object + properties: + arabic_text: + type: string + default: '' + translated_text: + type: string + default: '' + title: + type: string + default: '' + content: + type: string + default: '' + AboutUsRequest: + type: object + properties: + content: + type: string + default: '' + AdminNotification: + type: object + properties: + id: + type: integer + readOnly: true + title: + type: string + maxLength: 255 + message: + type: string + maxLength: 1024 + is_read: + type: boolean + notification_type: + type: string + nullable: true + maxLength: 50 + action: + type: string + maxLength: 50 + navigate_to: + type: string + nullable: true + maxLength: 255 + created_at: + type: string + format: date-time + readOnly: true + updated_at: + type: string + format: date-time + readOnly: true + user_fullname: + type: string + readOnly: true + user_email: + type: string + readOnly: true + user_id: + type: integer + readOnly: true + required: + - created_at + - id + - message + - title + - updated_at + - user_email + - user_fullname + - user_id + AdminNotificationRequest: + type: object + properties: + title: + type: string + minLength: 1 + maxLength: 255 + message: + type: string + minLength: 1 + maxLength: 1024 + is_read: + type: boolean + notification_type: + type: string + nullable: true + maxLength: 50 + action: + type: string + minLength: 1 + maxLength: 50 + navigate_to: + type: string + nullable: true + maxLength: 255 + required: + - message + - title + AdminUser: + type: object + properties: + id: + type: integer + readOnly: true + fullname: + type: string + nullable: true + title: Full Name + description: Full name of the user. + maxLength: 255 + email: + type: string + format: email + phone_number: + type: string + nullable: true + description: e.g., +1 555 1234567 + maxLength: 128 + avatar: + type: string + nullable: true + gender: + nullable: true + oneOf: + - $ref: '#/components/schemas/GenderEnum' + - $ref: '#/components/schemas/BlankEnum' + - $ref: '#/components/schemas/NullEnum' + birthdate: + type: string + format: date + nullable: true + info: + type: string + nullable: true + title: Bio / Info + skill: + type: string + nullable: true + title: Skill / Role + maxLength: 512 + city: + type: string + nullable: true + maxLength: 255 + country: + type: string + nullable: true + maxLength: 255 + device_id: + type: string + readOnly: true + device_os: + type: string + readOnly: true + user_agent: + type: string + readOnly: true + client_ip: + type: string + readOnly: true + fcm: + type: string + nullable: true + title: FCM Token + maxLength: 512 + user_type: + $ref: '#/components/schemas/UserTypeEnum' + is_active: + type: boolean + title: Active + description: Designates whether this user should be treated as active. + is_staff: + type: boolean + is_superuser: + type: boolean + title: Superuser status + description: Designates that this user has all permissions without explicitly + assigning them. + date_joined: + type: string + format: date-time + readOnly: true + last_login: + type: string + format: date-time + readOnly: true + nullable: true + auth_token: + type: string + readOnly: true + plain_password: + type: string + readOnly: true + required: + - auth_token + - client_ip + - date_joined + - device_id + - device_os + - email + - id + - last_login + - plain_password + - user_agent + AdminUserRequest: + type: object + properties: + fullname: + type: string + nullable: true + title: Full Name + description: Full name of the user. + maxLength: 255 + email: + type: string + format: email + minLength: 1 + phone_number: + type: string + nullable: true + description: e.g., +1 555 1234567 + maxLength: 128 + password: + type: string + writeOnly: true + minLength: 1 + avatar: + type: string + nullable: true + minLength: 1 + gender: + nullable: true + oneOf: + - $ref: '#/components/schemas/GenderEnum' + - $ref: '#/components/schemas/BlankEnum' + - $ref: '#/components/schemas/NullEnum' + birthdate: + type: string + format: date + nullable: true + info: + type: string + nullable: true + title: Bio / Info + skill: + type: string + nullable: true + title: Skill / Role + maxLength: 512 + city: + type: string + nullable: true + maxLength: 255 + country: + type: string + nullable: true + maxLength: 255 + fcm: + type: string + nullable: true + title: FCM Token + maxLength: 512 + user_type: + $ref: '#/components/schemas/UserTypeEnum' + is_active: + type: boolean + title: Active + description: Designates whether this user should be treated as active. + is_staff: + type: boolean + is_superuser: + type: boolean + title: Superuser status + description: Designates that this user has all permissions without explicitly + assigning them. + required: + - email + AppTypeEnum: + enum: + - google_play + - app_store + - direct + type: string + description: |- + * `google_play` - Google Play + * `app_store` - Apple App Store + * `direct` - Direct Download + AppVersion: + type: object + properties: + id: + type: integer + readOnly: true + version: + type: string + description: Application version in format X.Y.Z (e.g., 1.0.0) + pattern: ^\d+\.\d+\.\d+$ + maxLength: 20 + apk_file: + type: string + format: uri + nullable: true + readOnly: true + description: + type: string + description: Release notes and changes for this version + app_type: + allOf: + - $ref: '#/components/schemas/AppTypeEnum' + title: App Distribution Platform + downloads_count: + type: integer + maximum: 9223372036854775807 + minimum: 0 + format: int64 + is_active: + type: boolean + title: Active + description: Is this version currently active? + created_at: + type: string + format: date-time + readOnly: true + updated_at: + type: string + format: date-time + readOnly: true + required: + - apk_file + - created_at + - id + - updated_at + - version + BlankEnum: + enum: + - '' + Card: + type: object + properties: + card_number: + type: string + default: '' + card_name: + type: string + default: '' + whatsapp_number: + type: string + default: '' + CardRequest: + type: object + properties: + card_number: + type: string + default: '' + card_name: + type: string + default: '' + whatsapp_number: + type: string + default: '' + DeviceOsEnum: + enum: + - android + - apple + - web + type: string + description: |- + * `android` - Android + * `apple` - Apple iOS + * `web` - Web + ExchangeToken: + type: object + properties: + temp_token: + type: string + maxLength: 128 + required: + - temp_token + ExchangeTokenRequest: + type: object + properties: + temp_token: + type: string + minLength: 1 + maxLength: 128 + required: + - temp_token + FAQItem: + type: object + properties: + question: + type: string + default: '' + answer: + type: string + default: '' + FAQItemRequest: + type: object + properties: + question: + type: string + default: '' + answer: + type: string + default: '' + GenderEnum: + enum: + - male + - female + - other + type: string + description: |- + * `male` - Male + * `female` - Female + * `other` - Other + HealthCheckResponse: + type: object + properties: + status: + type: string + default: healthy + timestamp: + type: string + format: date-time + version: + type: string + default: 1.0.0 + required: + - timestamp + LocationHistory: + type: object + properties: + id: + type: integer + readOnly: true + lat: + type: number + format: double + nullable: true + title: Latitude + lon: + type: number + format: double + nullable: true + title: Longitude + country: + type: string + nullable: true + maxLength: 255 + city: + type: string + nullable: true + maxLength: 255 + selected_manually: + type: boolean + ip: + type: string + nullable: true + title: IP Address + maxLength: 255 + timezone: + type: string + nullable: true + maxLength: 60 + required: + - id + LocationHistoryRequest: + type: object + properties: + lat: + type: number + format: double + nullable: true + title: Latitude + lon: + type: number + format: double + nullable: true + title: Longitude + country: + type: string + nullable: true + maxLength: 255 + city: + type: string + nullable: true + maxLength: 255 + selected_manually: + type: boolean + ip: + type: string + nullable: true + title: IP Address + maxLength: 255 + timezone: + type: string + nullable: true + maxLength: 60 + Notification: + type: object + properties: + id: + type: integer + readOnly: true + title: + type: string + maxLength: 255 + message: + type: string + maxLength: 1024 + is_read: + type: boolean + notification_type: + type: string + nullable: true + maxLength: 50 + action: + type: string + maxLength: 50 + navigate_to: + type: string + nullable: true + maxLength: 255 + created_at: + type: string + format: date-time + readOnly: true + updated_at: + type: string + format: date-time + readOnly: true + required: + - created_at + - id + - message + - title + - updated_at + NotificationTemplate: + type: object + properties: + id: + type: integer + readOnly: true + notification_type: + type: string + maxLength: 50 + name: + type: string + maxLength: 100 + is_active: + type: boolean + title: + type: string + maxLength: 255 + body: + type: string + maxLength: 1024 + placeholders_info: + type: string + nullable: true + title: Allowed Placeholders Description + maxLength: 255 + required: + - id + - name + - notification_type + NotificationTemplateRequest: + type: object + properties: + notification_type: + type: string + minLength: 1 + maxLength: 50 + name: + type: string + minLength: 1 + maxLength: 100 + is_active: + type: boolean + title: + type: string + minLength: 1 + maxLength: 255 + body: + type: string + minLength: 1 + maxLength: 1024 + placeholders_info: + type: string + nullable: true + title: Allowed Placeholders Description + maxLength: 255 + required: + - name + - notification_type + NullEnum: + enum: + - null + PaginatedAdminNotificationList: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + $ref: '#/components/schemas/AdminNotification' + PaginatedAdminUserList: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + $ref: '#/components/schemas/AdminUser' + PaginatedNotificationList: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + $ref: '#/components/schemas/Notification' + PaginatedNotificationTemplateList: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + $ref: '#/components/schemas/NotificationTemplate' + PatchedAdminNotificationRequest: + type: object + properties: + title: + type: string + minLength: 1 + maxLength: 255 + message: + type: string + minLength: 1 + maxLength: 1024 + is_read: + type: boolean + notification_type: + type: string + nullable: true + maxLength: 50 + action: + type: string + minLength: 1 + maxLength: 50 + navigate_to: + type: string + nullable: true + maxLength: 255 + PatchedAdminUserRequest: + type: object + properties: + fullname: + type: string + nullable: true + title: Full Name + description: Full name of the user. + maxLength: 255 + email: + type: string + format: email + minLength: 1 + phone_number: + type: string + nullable: true + description: e.g., +1 555 1234567 + maxLength: 128 + password: + type: string + writeOnly: true + minLength: 1 + avatar: + type: string + nullable: true + minLength: 1 + gender: + nullable: true + oneOf: + - $ref: '#/components/schemas/GenderEnum' + - $ref: '#/components/schemas/BlankEnum' + - $ref: '#/components/schemas/NullEnum' + birthdate: + type: string + format: date + nullable: true + info: + type: string + nullable: true + title: Bio / Info + skill: + type: string + nullable: true + title: Skill / Role + maxLength: 512 + city: + type: string + nullable: true + maxLength: 255 + country: + type: string + nullable: true + maxLength: 255 + fcm: + type: string + nullable: true + title: FCM Token + maxLength: 512 + user_type: + $ref: '#/components/schemas/UserTypeEnum' + is_active: + type: boolean + title: Active + description: Designates whether this user should be treated as active. + is_staff: + type: boolean + is_superuser: + type: boolean + title: Superuser status + description: Designates that this user has all permissions without explicitly + assigning them. + PatchedNotificationTemplateRequest: + type: object + properties: + notification_type: + type: string + minLength: 1 + maxLength: 50 + name: + type: string + minLength: 1 + maxLength: 100 + is_active: + type: boolean + title: + type: string + minLength: 1 + maxLength: 255 + body: + type: string + minLength: 1 + maxLength: 1024 + placeholders_info: + type: string + nullable: true + title: Allowed Placeholders Description + maxLength: 255 + PatchedUserProfileRequest: + type: object + properties: + fcm: + type: string + minLength: 1 + description: Firebase Cloud Messaging token. + fullname: + type: string + minLength: 1 + avatar: + type: string + nullable: true + minLength: 1 + phone_number: + type: string + nullable: true + description: e.g., +1 555 1234567 + maxLength: 128 + password: + type: string + writeOnly: true + minLength: 1 + city: + type: string + nullable: true + maxLength: 255 + country: + type: string + nullable: true + maxLength: 255 + birthdate: + type: string + format: date + nullable: true + gender: + allOf: + - $ref: '#/components/schemas/GenderEnum' + description: |- + Select the user's gender. + + * `male` - Male + * `female` - Female + * `other` - Other + Support: + type: object + properties: + telegram_number: + type: string + default: '' + whatsapp_number: + type: string + default: '' + office_hours: + type: string + default: '' + SupportMessageCreate: + type: object + properties: + id: + type: integer + readOnly: true + sender_name: + type: string + maxLength: 255 + sender_email: + type: string + format: email + maxLength: 254 + subject: + type: string + maxLength: 255 + sender_phone: + type: string + nullable: true + maxLength: 128 + message: + type: string + created_at: + type: string + format: date-time + readOnly: true + required: + - created_at + - id + - message + - sender_email + - sender_name + - subject + SupportMessageCreateRequest: + type: object + properties: + sender_name: + type: string + minLength: 1 + maxLength: 255 + sender_email: + type: string + format: email + minLength: 1 + maxLength: 254 + subject: + type: string + minLength: 1 + maxLength: 255 + sender_phone: + type: string + nullable: true + maxLength: 128 + message: + type: string + minLength: 1 + required: + - message + - sender_email + - sender_name + - subject + SupportRequest: + type: object + properties: + telegram_number: + type: string + default: '' + whatsapp_number: + type: string + default: '' + office_hours: + type: string + default: '' + TokenObtainPair: + type: object + properties: + access: + type: string + readOnly: true + refresh: + type: string + readOnly: true + required: + - access + - refresh + TokenObtainPairRequest: + type: object + properties: + email: + type: string + writeOnly: true + minLength: 1 + password: + type: string + writeOnly: true + minLength: 1 + required: + - email + - password + TokenRefresh: + type: object + properties: + access: + type: string + readOnly: true + refresh: + type: string + required: + - access + - refresh + TokenRefreshRequest: + type: object + properties: + refresh: + type: string + minLength: 1 + required: + - refresh + TokenVerifyRequest: + type: object + properties: + token: + type: string + writeOnly: true + minLength: 1 + required: + - token + UserFCM: + type: object + properties: + fcm: + type: string + nullable: true + title: FCM Token + maxLength: 512 + UserFCMRequest: + type: object + properties: + fcm: + type: string + nullable: true + title: FCM Token + maxLength: 512 + UserGuest: + type: object + properties: + device_id: + type: string + fcm: + type: string + device_os: + $ref: '#/components/schemas/DeviceOsEnum' + lat: + type: string + nullable: true + maxLength: 255 + lon: + type: string + nullable: true + maxLength: 255 + timezone: + type: string + nullable: true + UserGuestRequest: + type: object + properties: + device_id: + type: string + minLength: 1 + fcm: + type: string + minLength: 1 + device_os: + $ref: '#/components/schemas/DeviceOsEnum' + lat: + type: string + nullable: true + maxLength: 255 + lon: + type: string + nullable: true + maxLength: 255 + timezone: + type: string + nullable: true + UserLogin: + type: object + properties: + token: + type: string + readOnly: true + nullable: true + fullname: + type: string + readOnly: true + nullable: true + avatar: + type: string + readOnly: true + nullable: true + password: + type: string + fcm: + type: string + device_id: + type: string + timezone: + type: string + nullable: true + required: + - avatar + - fullname + - password + - token + UserLoginRequest: + type: object + properties: + email: + type: string + format: email + writeOnly: true + minLength: 1 + password: + type: string + minLength: 1 + fcm: + type: string + minLength: 1 + device_id: + type: string + minLength: 1 + timezone: + type: string + nullable: true + required: + - email + - password + UserProfile: + type: object + properties: + id: + type: integer + readOnly: true + device_id: + type: string + readOnly: true + nullable: true + fcm: + type: string + description: Firebase Cloud Messaging token. + fullname: + type: string + slug: + type: string + readOnly: true + nullable: true + pattern: ^[-a-zA-Z0-9_]+$ + avatar: + type: string + nullable: true + email: + type: string + format: email + readOnly: true + nullable: true + title: Email Address + description: User primary email address. + phone_number: + type: string + nullable: true + description: e.g., +1 555 1234567 + maxLength: 128 + info: + type: string + readOnly: true + nullable: true + title: Bio / Info + skill: + type: string + readOnly: true + nullable: true + title: Skill / Role + city: + type: string + nullable: true + maxLength: 255 + country: + type: string + nullable: true + maxLength: 255 + birthdate: + type: string + format: date + nullable: true + gender: + allOf: + - $ref: '#/components/schemas/GenderEnum' + description: |- + Select the user's gender. + + * `male` - Male + * `female` - Female + * `other` - Other + saved_location: + type: string + readOnly: true + required: + - device_id + - email + - id + - info + - saved_location + - skill + - slug + UserProfileRequest: + type: object + properties: + fcm: + type: string + minLength: 1 + description: Firebase Cloud Messaging token. + fullname: + type: string + minLength: 1 + avatar: + type: string + nullable: true + minLength: 1 + phone_number: + type: string + nullable: true + description: e.g., +1 555 1234567 + maxLength: 128 + password: + type: string + writeOnly: true + minLength: 1 + city: + type: string + nullable: true + maxLength: 255 + country: + type: string + nullable: true + maxLength: 255 + birthdate: + type: string + format: date + nullable: true + gender: + allOf: + - $ref: '#/components/schemas/GenderEnum' + description: |- + Select the user's gender. + + * `male` - Male + * `female` - Female + * `other` - Other + UserRecoverPassword: + type: object + description: |- + Validates that an email is provided and is in a valid format + without checking for database uniqueness. + properties: + email: + type: string + format: email + required: + - email + UserRecoverPasswordRequest: + type: object + description: |- + Validates that an email is provided and is in a valid format + without checking for database uniqueness. + properties: + email: + type: string + format: email + minLength: 1 + required: + - email + UserRegister: + type: object + properties: + id: + type: integer + readOnly: true + fullname: + type: string + nullable: true + title: Full Name + description: Full name of the user. + maxLength: 255 + email: + type: string + format: email + fcm: + type: string + nullable: true + required: + - email + - fullname + - id + UserRegisterRequest: + type: object + properties: + fullname: + type: string + nullable: true + title: Full Name + description: Full name of the user. + maxLength: 255 + email: + type: string + format: email + minLength: 1 + password: + type: string + writeOnly: true + minLength: 1 + fcm: + type: string + nullable: true + device_id: + type: string + writeOnly: true + nullable: true + required: + - email + - fullname + UserResetPasswordRequest: + type: object + properties: + password: + type: string + writeOnly: true + minLength: 1 + required: + - password + UserTypeEnum: + enum: + - client + - student + - professor + - consultant + - admin + - super_admin + - regional_admin + - institution_admin + - editor + - viewer + type: string + description: |- + * `client` - Client / User + * `student` - Student / Member + * `professor` - Professor / Scholar + * `consultant` - Consultant + * `admin` - Admin + * `super_admin` - Super Admin + * `regional_admin` - Regional Admin + * `institution_admin` - Institution Admin + * `editor` - Editor + * `viewer` - Viewer + UserVerify: + type: object + properties: + code: + type: string + maxLength: 6 + email: + type: string + format: email + device_id: + type: string + maxLength: 255 + required: + - code + - email + UserVerifyRequest: + type: object + properties: + code: + type: string + minLength: 1 + maxLength: 6 + email: + type: string + format: email + minLength: 1 + device_id: + type: string + minLength: 1 + maxLength: 255 + required: + - code + - email + WebUserRegister: + type: object + properties: + id: + type: integer + readOnly: true + fullname: + type: string + nullable: true + title: Full Name + description: Full name of the user. + maxLength: 255 + email: + type: string + format: email + fcm: + type: string + nullable: true + required: + - email + - fullname + - id + WebUserRegisterRequest: + type: object + properties: + fullname: + type: string + nullable: true + title: Full Name + description: Full name of the user. + maxLength: 255 + email: + type: string + format: email + minLength: 1 + password: + type: string + writeOnly: true + minLength: 1 + fcm: + type: string + nullable: true + required: + - email + - fullname + - password + securitySchemes: + cookieAuth: + type: apiKey + in: cookie + name: sessionid + jwtAuth: + type: http + scheme: bearer + bearerFormat: JWT + tokenAuth: + type: apiKey + in: header + name: Authorization + description: Token-based authentication with required prefix "Token"